0
votes

I'm having trouble with constructors in derived classes. Lets say I have the simple code below here with one base class Base and two classes whom inherits from Base, Derived1 and Derived2.

I want Derived2 to hold a pointer to Base, which could point either to Base or Derived1. I cannot manage to write the constructor for this tho. If I pass in a Derived1 object I get a empty Base once inside the constructor.

Class Base
{
public:
      Base(int a): m_a(a)
      {
      }

protected:
         int m_a;
};


//First derived class of base
class Derived1 : public Base
{
public:
        Derived1(double c): m_c(c)
        {
        }

private:
        double m_c;
};


//Second derived class of Base
class Derived2 : public Base
{
public:
        Derived2(Base b, int k): m_b(&b), m_k(k)
        {
        }

private:
        int m_k;
        Base* m_b;
};


int main()
{
    Base b(2);
    Derived1 d1(3.0);


    Derived2 d2(d1, 3);
    Derived2 d3(b, 4);
}
3
Your looking for composition rather than inheritance there.IdeaHat
... and you should know that Derived2 instance will end up with a completely illegitimate m_b value after construction. You're saving the address of a local variable (the copy Base b, which you likely did not intend to be sliced, but none-the-less is.)WhozCraig
Add virtual ~Base() {} to the base class and use RTTI (dynamic_cast) as needed. Maybe you get rid of all derived member data and have a union in base (with an additional member describing the type (int, double, ...))user2249683
you are passing a copy, pass base as a pointer or reference: Derived2(Base &b, int k): m_b(b), m_k(k)Ray Tayek

3 Answers

0
votes

You likely want to accept a Base* in your constructor, rather than an actual Base instance:

Derived2(Base* b, int k) : m_b(b), m_k(k)
{
}

Then you can pass the address-of the instance that you want your Derived2 instance to point to:

Derived2 d2(&d1, 3);
Derived2 d3(&b, 4);

Note that you should give them thought to the ownership of the Base object being pointed to in the Derived2 instances. Additionally, if the Derived2 object persists after the passed Base object has been deleted, accessing m_b will result in undefined behavior. If you can use C++11, consider passing and storing std::shared_ptr<Base> instead of a raw pointer.

0
votes

There are many problems here. Let's ignore the design problems with Derived2 for now (naked pointers are evil).

Focussing on Derived1...

Derived1 is derived from Base, which means it is a Base. Base has only a 1-argument constructor (and therefore no default constructor)

Derived1 has a 1-argument constructor also, but this argument is initialising Derived1's data (m_c).

Since Derived is a Base, the Base part of it must be constructed at construction time. Since you must construct Base, and base has only a 1-argument constructor, you must specifically mention this in the constructor of Derived1.

Like this:

class Derived1 : public Base
{
public:
    Derived1(double c, int some_value_for_base)
    : Base(some_value_for_base)
    , m_c(c)
    {
    }

...
};
0
votes

I understand that you want Derived2 to hold a pointer to another Base object.

First issue: your constructor uses a value argument for the base object:

    Derived2(Base b, int k): m_b(&b), m_k(k)

This means that when it gets called, a temporary copy of the parameter passed for b is made, and you will store the address of this temporary object. Of course, once you leave the statement calling the constructor, this address gets invalid. Segfault guaranteed sooner or later !

Solution: pass argument by reference (rest of code unchanged):

    Derived2(Base& b, int k): m_b(&b), m_k(k)

Second issue: Your code doesn't compile, because Base doesn't have default constructor and the constructor for Derived1 and Derived2 do not provide for a valid Base in their initialisation list.

Solution 1: Either provide an explicit base intialisation in ALL derived constructors. For example :

    Derived2(Base& b, int k) : m_b(&b), m_k(k), Base(k)  // is k the right value ? 
    { ... }

Solution 2: Or consider using a default value for the parameter of Base constructor:

    Base(int a=0): m_a(a)  // default parameter is 0 
    { ... }