How can I initialize a derived class using its attributes and the base class constructor?

112 Views Asked by At

Starting from a base class, I want to create some derived classes, which differs from one another for the value of a number of data members. These different attributes are used in the BaseClass constructor to inizialize other data members. Below you can find a simplified example of what I mean;

class BaseClass {
public:
    BaseClass(int a, double b, int c, std::string d) {
        // Do stuff depending also on d
    }
    double f;  // Inizialized in the BaseClass constructor
};

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d) {};
    std::string d = "Hello";
};

class DerivedClass2 : public BaseClass {
public:
    DerivedClass2(int a, double b, int c) : BaseClass(a, b, c, d) {};
    std::string d = "Goodbye";
};

However, I am surely doing something wrong, since I get warning: field 'd' is uninitialized when used here [-Wuninitialized]. What is the right way to implement this?

3

There are 3 best solutions below

2
Shreeyash Shrestha On

In your given code, i think you missed a point here. in the code:

class BaseClass {
public:
    BaseClass(int a, double b, int c, std::string d) {
        // Do stuff depending also on d
    }
    double f;  // Inizialized in the BaseClass constructor
};

you have set 4 values in the constructor for the base class.. namely int a, double b, int c, std::string d This means whenever you call the constructor of the base class, you are supposed to pass in 4 arguments whereas in this code:


class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d), d(d) {}
    std::string d = "Hello";
};

class DerivedClass2 : public BaseClass {
public:
    DerivedClass2(int a, double b, int c) : BaseClass(a, b, c, d), d(d) {}
    std::string d = "Goodbye";
};

in this both class, you have been passing something like a d(d) which i dont know what is . In other words, just remove the d(d).

EDIT: i found you have missed something here as well:

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d), d(d) {}
    std::string d = "Hello";
};

you placed the block of code: std::string d="Hello"; outside the scope of the constructor. Make these changes:

class BaseClass {
public:
    BaseClass(int a, double b, int c, std::string d) {
        // Do stuff depending also on d
    }
    double f;  // Inizialized in the BaseClass constructor
};

class DerivedClass1 : public BaseClass {
public:
 std::string d="Anything you want to initialize d to is here";
    DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, d) {
   //Constructor code
}
};

class DerivedClass2 : public BaseClass {
public:
 std::string d="Same here as well";
    DerivedClass2(int a, double b, int c) : BaseClass(a, b, c, d) {
    //Constructor code
}
};

and you're good to go. Hope that helps!!!

0
Miles Budnek On

Your issue is that the base sub-object is the first thing that gets initialized. That is, this:

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c)
      : BaseClass(a, b, c, d)
    {};
    std::string d = "Hello";
};

Is essentially equivalent to this:

class DerivedClass1 : public BaseClass {
public:
    DerivedClass1(int a, double b, int c)
      : BaseClass(a, b, c, d),
        d("Hello")
    {};
    std::string d;
};

d is passed to BaseClass's constructor before it gets initialized by DerivedClass1's constructor.

To work around this you could introduce another base class that holds the extra member:

class DerivedBase {
public:
    DerivedBase(std::string d) : d(d) {}
    std::string d;
};

class DerivedClass1 : public DerivedBase, public BaseClass {
public:
    DerivedClass1(int a, double b, int c)
      : DerivedBase("Hello"),
        BaseClass(a, b, c, d)
    {}
};

Since base classes are initialized in the order they're listed in the base-clause of the class declaration, DerivedBase will be initialized before BaseClass, so d will have been initialized before it gets passed to BaseClass's constructor.

1
user1806566 On

The problem is that during derived class construction, the base class constructor runs before the derived class members are initialized. That's why the compiler complains that d is uninitialized when you call the base class constructor with d as an argument.

If we leave your declarations as-is, I think you need to repeat yourself to get what you want.

class DerivedClass1 : public BaseClass {
public:
  DerivedClass1(int a, double b, int c) : BaseClass(a, b, c, "Hello") {};
  std::string d = "Hello";
};

Of course, repeating yourself isn't a good thing, but avoiding it would mean refactoring your code. d is clearly a BaseClass concept (or it wouldn't need it in its constructor). If you moved the data member to BaseClass, then the initialization order issue would be moot.