user487100
user487100

Reputation: 918

set the base object of derived object?

This is a basic concept question. If I have a class that Derived that inherits from Base, and I instantiate a new Derived object, can I set it's Base object to a specific Base object of my choosing so that all calls base class methods are redirected to this particular base object?

something like this:

class Base
{
protected:
    string name;
public:
    Base(string n) { name = n}
    void doSomething(){cout << name << "\n";}
};

class Derived : public Base
{
public:
     Derived(string n) : Base(n) {}

int main()
{
    Derived* d = new Derived("original base"); //create a derived
    d->doSomething(); // prints "original base"
    Base* rB = new Base("replacement base"); // create a new base object
    ((Base*) d) = rB; // replace the base object of d with a new one (pretend code)
    d->doSomething(); // prints "replacement base"

    return 0;
}

I'm sure I made all sorts of errors in that simple code, because my skill level is low, but just for the idea.

Is this possible in C++? We can slice the derived information off of an object, so can we separate and replace the components in a chain of inheritance?

Why would I want to do this?

Consider the mixin lilies: (again, forgive syntax errors)

template <class T> class MyMixin : public T
{
public:
    MyMixin(T desiredBaseObject)
    { 
        // do something to set the desired base 
        // object of this class to desiredBaseObject.
    }
};

RandomClass1 dog(int i = 0);  
RandomClass2 cat(double i = 0.0);
MyMixin< RandomClass1 > mixin1(dog);
MyMixin< RandomClass2 > mixin2(cat);

In this case, if we could set the base object of the mixin to any desired object, we could use constructors with any parameter list in our mixin without the mixin needing to know anything about it. Also, the mixin could be used like a decorator without the need for a common interface amongst decorators.

Thanks for the answers. Since we can slice off the derived part of an object, it seems like the base and derived information lives separately. Could someone comment on this? Could we access some internal table, like the vtables I hear so much about (I don't know anything about this type of stuff, so maybe this is not applicable), and accomplish this?

@Benoît

Could you explain why only 1 and 4 work, but 2 and 3 do not? class Base { protected: std::string name; public: Base(std::string n) { name = n; }

    virtual void doSomething()
    {
        cout << name << "\n";
    }
};

class Derived : public Base
{
public:
    int x;
    Derived(std::string n) : Base(n)
    {
        x = 5;
    }

    void printX()
    {
        cout << "x = " << x << "\n";
        x++;
    }
};


Derived* d1 = new Derived("original 1");
d1->doSomething();
d1->printX();
Base* rb1 = new Base("new 1");
*static_cast<Base*>(d1) = *rb1;
d1->doSomething();
d1->printX();
cout << "\n\n";

Derived d2 = Derived("original 2");
d2.doSomething();
d2.printX();
Base b2 = Base("new 2");
static_cast<Base>(d2) = b2;
d2.doSomething();
d2.printX();
cout << "\n\n";

Derived d3("original 3");
d3.doSomething();
d3.printX();
Base b3("new 3");
static_cast<Base>(d3) = b3;
d3.doSomething();
d3.printX();
cout << "\n\n";

Derived d4("original 4");
d4.doSomething();
d4.printX();
Base b4("new 4");
*static_cast<Base*>(&d4) = *&b4;
d4.doSomething();
d4.printX();
cout << "\n\n";

this will print:

original 1 x = 5 new 1 x = 6

original 2 x = 5 original 2 x = 6

original 3 x = 5 original 3 x = 6

original 4 x = 5 new 4 x = 6

Why does this only work with when using a pointer?

Upvotes: 1

Views: 1636

Answers (7)

Beno&#238;t
Beno&#238;t

Reputation: 3543

I'm not questioning why you want to do this, but it's perfectly safe do it unless your inheritance breaks the ISA relationship (eg Derived is a restricted subset of Base, eg a Square is not a Rectangle since it is possible to resize only one dimension of a Rectangle but impossible to do so with a Square).

*static_cast<Base*>(d) = *rB;

(works also with references)

or you can write a little function (you will find lots of functions doing this):

template<typename T>
T& assign(T& to, const T& from)
{
  return to = from;
}

assign<Base>(*d, *rB);

and anyway, you do this every time you overload/redefine operator=

Derived& operator=(const Derived& other)
{
  // prettier than the cast notation
  Base::operator=(other);

  // do something specific to Derived;
  this->name += " (assigned)";

  return *this;
}

Upvotes: 3

Nick
Nick

Reputation: 5805

You could combine inheritance & composition:

class A {
    string name;
public: A(const char* s) : name(string(s)) {}
        virtual void m() { cout << name << endl; }
};

class B : A {
public:
    B(const char* s) : A(s), a(0) {}
    void m() { if (a) a->m(); else A::m(); }
    A* a;
};

int main() {
    B b("b");
    b.m(); // prints b
    b.a = new A("a");
    b.m(); // prints a
}

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 476980

Inheritance is a property of types, not of objects. The type "Derived" inherits from the type "Base". You can make objects of type "Derived" (Derived x;), and you can also make objects of type "Base" (Base y, unless that's forbidden), but each of those objects are complete, fully-fledged objects with no "replaceable parts".

The point of type inheritance is that you may treat an object of type "Derived" as if it was an object of type "Base" (as long as you refer to it by reference or pointer), that is, if you have a function void foo(Base & b);, then you may call foo(x). But foo can only access those parts of x which are inherited from "Base"!

Upvotes: 1

Yochai Timmer
Yochai Timmer

Reputation: 49231

Inheritance = IS A relation.

Composition = HAS A relation.

You're describing a class that has an object of type A where you can set its instance.
So you need to use composition - Make a class that hold a member of type A

Upvotes: 1

David Thornley
David Thornley

Reputation: 57036

No.

Why would you want to do this? If two Deriveds are supposed to have the exact same Base, such that modifications through one Derived show up in the other, you need to have some sort of pointer to Base in each derived, making this composition, not inheritance.

If you want to change the data in the Derived's Base, write a function to do that, a little like a copy assignment operator for Base.

Alternately, you could make a new constructor for Derived that would take a Base and a Derived, and take Base information from the Base and Derived information from the Derived.

Upvotes: 0

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272467

No, you cannot do that.

You have (at least) a couple of options:

  • Create a new Derived object, parameterised by a mixture of parameters from the two objects you wish to combine.
  • Create some setter methods in the Base class, that allow you to change its parameters/state later in its lifetime.

Upvotes: 0

Billy ONeal
Billy ONeal

Reputation: 106530

No. If you need to do this, you should use composition, not inheritance.

(I'm answering the more general question -- in your specific case where you just want to change the string you can just change name from within the derived class)

Upvotes: 3

Related Questions