Home > Software engineering >  In C , whether a derived object can first construct derived part then construct base part?
In C , whether a derived object can first construct derived part then construct base part?

Time:02-18

As we know, In C , if a derived class B: public A {}, derives from its base class A. When we call class B's constructor to generate an instance of B, we have to first call base A's constructor and then initialize derived part. So why we couldn't swap the sequence, i.e.first initialize derived part then call base's constructor? If do so, what problem will it lead to?

CodePudding user response:

So why we couldn't swap the sequence, i.e.first initialize derived part then call base's constructor? If do so, what problem will it lead to?

That way the derived class contructor wouldn't be able to use the base sub object. That would be an unnecessary limitation.

CodePudding user response:

I would like to add that there is room to play with the strict order concerning the construction of classes.

Say, we have to following intention to implement:

  • a base class which reads something from an arbitrary stream object
  • a derived class specialized to do so for a file stream.

This is how the base class could look like:

#include <iostream>

struct Reader {
  // stream to read from
  std::istream& in;

  // constructor.
  Reader(std::istream& in): in(in) { }

  // intentionally not available (would break RAII)
  Reader(const Reader&) = delete;

  // read function
  void read();

};

A derived class for convenient reading of files:

#include <fstream>
#include <string>
#include "Reader.h"

struct FileReader: Reader {

  // file stream to read from
  std::ifstream fIn;

  // constructor
  FileReader(const std::string& filePath);

};

So, here we are: We have to initialize fIn before constructing the base class Reader.

This is in fact a simplified real-world problem I once faced in my daily business, and I came up with the following solution:

I introduced yet another base class:

struct FStream {
  std::ifstream fIn;
  FStream(const std::string& filePath): fIn(filePath) { }
};

struct FileReader: FStream, Reader {

  // constructor
  FileReader(const std::string& filePath):
    FStream(filePath),
    Reader(FStream::fIn)
  { }

};

Relying on the defined order how base classes and members are initialized (in the strict order how declared i.e. from left to right and top to down), this opens the file stream fIn before the base class Reader is initialized with the reference to fIn.

A complete MCVE on coliru to demonstrate this in action:

// Reader.h:

#include <iostream>

struct Reader {
  // stream to read from
  std::istream& in;

  // constructor.
  Reader(std::istream& in): in(in) { }

  // intentionally not available (would break RAII)
  Reader(const Reader&) = delete;

  // read function
  void read();

};

// Reader.cc:

#include <string>

//#include "Reader.h"

void Reader::read()
{
  for (std::string line; std::getline(in, line);) std::cout << "Read: " << line << '\n';
}

// FileReader.h:

#include <fstream>
#include <string>
//#include "Reader.h"

struct FStream {
  std::ifstream fIn;
  FStream(const std::string& filePath): fIn(filePath) { }
};

struct FileReader: FStream, Reader {

  // constructor
  FileReader(const std::string& filePath):
    FStream(filePath),
    Reader(FStream::fIn)
  { }

};

// main.cpp:

//#include "FileReader.h"

int main()
{
  FileReader reader("./main.cpp");
  reader.read();
}

Output:

Read: // Reader.h:
Read: 
Read: #include <iostream>
Read: 
Read: struct Reader {
Read:   // stream to read from
Read:   std::istream& in;
Read: 
Read:   // constructor.
Read:   Reader(std::istream& in): in(in) { }
Read: 
Read:   // intentionally not available (would break RAII)
Read:   Reader(const Reader&) = delete;
Read: 
Read:   // read function
Read:   void read();
Read: 
Read: };
Read: 
Read: // Reader.cc:
Read: 
Read: #include <string>
Read: 
Read: //#include "Reader.h"
Read: 
Read: void Reader::read()
Read: {
Read:   for (std::string line; std::getline(in, line);) std::cout << "Read: " << line << '\n';
Read: }
Read: 
Read: // FileReader.h:
Read: 
Read: #include <fstream>
Read: #include <string>
Read: //#include "Reader.h"
Read: 
Read: struct FStream {
Read:   std::ifstream fIn;
Read:   FStream(const std::string& filePath): fIn(filePath) { }
Read: };
Read: 
Read: struct FileReader: FStream, Reader {
Read: 
Read:   // constructor
Read:   FileReader(const std::string& filePath):
Read:     FStream(filePath),
Read:     Reader(FStream::fIn)
Read:   { }
Read: 
Read: };
Read: 
Read: // main.cpp:
Read: 
Read: //#include "FileReader.h"
Read: 
Read: int main()
Read: {
Read:   FileReader reader("./main.cpp");
Read:   reader.read();
Read: }
  •  Tags:  
  • c
  • Related