danijar
danijar

Reputation: 34185

Is there a way to create a derived instance from a base instance?

I want to inject some basic information into a derived class that it can build on. The derived class shouldn't care about initializing those information, it should be just there.

That alone would be easily possible through inheritance. But the problem is that the base class doesn't know the values on its own. Instead, they need to be passed in as parameter. However, since the derived class should not need to take care of that, tunneling the parameters through the derived constructor which calls the base constructor with it is no option.

The only solution I can think of is to make the information available statically so that the base class can get them without help. But I'd like to avoid that.

Is there some way of first creating and initializing the base class and extending the instance to a derived type afterwards? If not, how can I achieve this order of creation and dependencies using the available features of C++?

#include <string>
#include <iostream>
using namespace std;

class Base {
public:
    Base(string name, int age) : name(name), age(age) {}
protected:
    const string name;
    int age = 0;
};

class Derived : public Base {
    Derived() { // No parameters here, no call to base constructor
        cout << "My name is " << name << " and I'm " << age << "." << endl;
    }
}

Base base("Peter", 42);
Derived derived(base); // "My name is Peter and I'm 42."

Upvotes: 6

Views: 710

Answers (3)

Alexander Gessler
Alexander Gessler

Reputation: 46617

Extending an already-allocated type to a derived type is not possible for a reason: if the derived type added fields, how would you determine the correct size upfront?

A possible way is only a constructor accepting a Base instance, or maybe an operator=.

However you may want to consider using composition over inheritance in this example. If Base only serves as template for Derived, it is not a good example of an inheritance relationship.

Upvotes: 5

Alex Kleiman
Alex Kleiman

Reputation: 709

One option would be to use composition, meaning that Base would be an instance variable of Derived:

#include <string>
#include <iostream>
using namespace std;

class Base {
public:
    Base(string name, int age) : name(name), age(age) {}
    const string name() { return name; }
    int age() { return age; }
protected:
    const string name;
    int age = 0;
};

class Derived {
    Derived(Base b): base(b) { // No parameters here
        cout << "My name is " << base.name() << " and I'm "
             << base.age() << "." << endl;
    }

private:
    Base base;    
}

Base base("Peter", 42);
Derived derived(base); // "My name is Peter and I'm 42."

Notice how Derived no longer extends Base (perhaps the names would need to be changed), and that every call to an instance variable in Base is now a method call.

Upvotes: 3

Kerrek SB
Kerrek SB

Reputation: 477110

"The information should just be there" sounds to me like it allows two possible interpretations:

  • The information is in fact globally constant and can be hard-coded:

    Derived() : Base("Peter", 42) {}
    
  • What you really meant was that "the base should just be there":

    Derived(const Base & b) : Base(b) {}
    

Upvotes: 6

Related Questions