Join the Stack Overflow Community
Stack Overflow is a community of 6.5 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I have a bunch of classes which all inherit the same attributes from a common base class. The base class implements some virtual functions that work in general cases, whilst each subclass re-implements those virtual functions for a variety of special cases.

Here's the situation: I want the special-ness of these sub-classed objects to be expendable. Essentially, I would like to implement an expend() function which causes an object to lose its sub-class identity and revert to being a base-class instance with the general-case behaviours implemented in the base class.

I should note that the derived classes don't introduce any additional variables, so both the base and derived classes should be the same size in memory.

I'm open to destroying the old object and creating a new one, as long as I can create the new object at the same memory address, so existing pointers aren't broken.

The following attempt doesn't work, and produces some seemingly unexpected behaviour. What am I missing here?

#include <iostream>

class Base {
public:
    virtual void whoami() { 
        std::cout << "I am Base\n"; 
    }
};

class Derived : public Base {
public:
    void whoami() {
        std::cout << "I am Derived\n";
    }
};

Base* object;

int main() {
    object = new Derived; //assign a new Derived class instance
    object->whoami(); //this prints "I am Derived"

    Base baseObject;
    *object = baseObject; //reassign existing object to a different type
    object->whoami(); //but it *STILL* prints "I am Derived" (!)

    return 0;
}
share|improve this question
2  
Remember that C++ is not a dynamic language, once it's compiled it's all fixed. – Some programmer dude 17 hours ago
8  
What you seem to be asking for is an application of placement new but I won't provide an answer -- it's bad design IMO. – matb 17 hours ago
5  
Maybe you can use the strategy design pantern instead of a class hierachy – manni66 16 hours ago
3  
@Someprogrammerdude: That is too strong. There's a reason we have something called dynamic_cast. While it's true that an object never changes its type, we may be using expressions of various compatible types to refer to that object. In particular, we may use base classes. Ex. Base* p = rand() ? new Derived1 : new Derived2;. While the static type of p is fixed, the dynamic type of *p isn't. – MSalters 12 hours ago
1  
The error in *object = baseObject strongly hints that you lack understanding of the very foundations of inheritance and polymorphism. Once you get over that, you'll probably discover some obvious answer, eg that what you wanted was composition instead of inheritance or something just as trivial. – Agent_L 12 hours ago

10 Answers 10

You can at the cost of breaking good practices and maintaining unsafe code. Other answers will provide you with nasty tricks to achieve this.

I dont like answers that just says "you should not do that", but I would like to suggest there probably is a better way to achieve the result you seek for.

The strategy pattern as suggested in a comment by @manni66 is a good one.

You should also think about data oriented design, since a class hierarchy does not look like a wise choice in your case.

share|improve this answer
    
When he does *object = baseObject, does anyone know whether the vtable in baseObject gets copied over to the derived object? If so, then when he calls object->whoamI() won't that call the base version of the function? – Titone Maurice 10 hours ago
    
Never mind, it obviously doesn't. In my Implementation the vtable seems to be 8 bytes and it's not copied over. Interestingly though, if I memcpy sizeof(Base) instead of assigning it, it calls the Base version. This seems like a cool feature to have. – Titone Maurice 9 hours ago
    
@TitoneMaurice: I've heard Undefined Behavior described using many invectives, but this is the first time I've heard it called "cool". – Ben Voigt 5 hours ago
    
@TitoneMaurice Object slicing (at least, AFAICT) – QPaysTaxes 5 hours ago
    
@QPaysTaxes: Well, the OP stipulated that Base and Derived are the same size; and you'd probably use a static_assert to enforce that at compile-time. (Of course, it'd still be undefined behavior.) – ruakh 4 hours ago

Yes and no. A C++ class defines the type of a memory region that is an object. Once the memory region has been instantiated, its type is set. You can try to work around the type system sure, but the compiler won't let you get away with it. Sooner or later it will shoot you in the foot, because the compiler made an assumption about types that you violated, and there is no way to stop the compiler from making such assumption in a portable fashion.

However there is a design pattern for this: It's "State". You extract what changes into it's own class hierarchy, with its own base class, and you have your objects store a pointer to the abstract state base of this new hierarchy. You can then swap those to your hearts content.

share|improve this answer
    
I think the pattern you're describing is more commonly referred to as the strategy pattern – QPaysTaxes 5 hours ago

You can do what you're literally asking for with placement new and an explicit destructor call. Something like this:

#include <iostream>
#include <stdlib.h>

class Base {
public:
    virtual void whoami() { 
        std::cout << "I am Base\n"; 
    }
};

class Derived : public Base {
public:
    void whoami() {
        std::cout << "I am Derived\n";
    }
};

union Both {
    Base base;
    Derived derived;
};

Base *object;

int
main() {
    Both *tmp = (Both *) malloc(sizeof(Both));
    object = new(&tmp->base) Base;

    object->whoami(); 

    Base baseObject;
    tmp = (Both *) object;
    tmp->base.Base::~Base();
    new(&tmp->derived) Derived; 

    object->whoami(); 

    return 0;
}

However as matb said, this really isn't a good design. I would recommend reconsidering what you're trying to do. Some of other answers here might also solve your problem, but I think anything along the idea of what you're asking for is going to be kludge. You should seriously consider designing your application so you can change the pointer when the type of the object changes.

share|improve this answer
2  
I considered (but didn't) voting down because the first sentence is wrong. You can not change the class of an object. One can replace an object with another one of a different class, as you do in your code. – Daniel Jour 14 hours ago
2  
I'm downvoting for precisely that reason. Let me know when it's fixed. – Lightness Races in Orbit 13 hours ago
    
Does this trigger undefined behaviour? – Kos 10 hours ago
2  
The second ` object->whoami` is undefined behavior. The pointer to base is pointing to a destroyed object; no aliasing is permitted without going back through a pointer-to-derived here as far as I know. – Yakk 9 hours ago

In addition to other answers, you could use function pointers (or any wrapper on them, like std::function) to achieve the necessary bevahior:

void print_base(void) {
    cout << "This is base" << endl;
}

void print_derived(void) {
    cout << "This is derived" << endl;
}

class Base {
public:
    void (*print)(void);

    Base() {
        print = print_base;
    }
};

class Derived : public Base {
public:
    Derived() {
        print = print_derived;
    }
};

int main() {
    Base* b = new Derived();
    b->print(); // prints "This is derived"
    *b = Base();
    b->print(); // prints "This is base"
    return 0;
}

Also, such function pointers approach would allow you to change any of the functions of the objects in run-time, not limiting you to some already defined sets of members implemented in derived classes.

share|improve this answer
    
Also called strategy pattern – WorldSEnder 14 hours ago

You can by introducing a variable to the base class, so the memory footprint stays the same. By setting the flag you force calling the derived or the base class implementation.

#include <iostream>

class Base {
public:
    Base() : m_useDerived(true)
    {
    }

    void setUseDerived(bool value)
    {
        m_useDerived = value;
    }

    void whoami() {
        m_useDerived ? whoamiImpl() : Base::whoamiImpl();
    }

protected:
    virtual void whoamiImpl() { std::cout << "I am Base\n"; }

private:
    bool m_useDerived;
};

class Derived : public Base {
protected:
    void whoamiImpl() {
        std::cout << "I am Derived\n";
    }
};

Base* object;

int main() {
    object = new Derived; //assign a new Derived class instance
    object->whoami(); //this prints "I am Derived"

    object->setUseDerived(false);
    object->whoami(); //should print "I am Base"

    return 0;
}
share|improve this answer

No it's not possible to change the type of an object once instantiated.

*object = baseObject; doesn't change the type of object, it merely calls a compiler-generated assignment operator.

It would have been a different matter if you had written

object = new Base;

(remembering to call delete naturally; currently your code leaks an object).

C++11 onwards gives you the ability to move the resources from one object to another; see

http://en.cppreference.com/w/cpp/utility/move

share|improve this answer
    
But this would change the address of the object. Existing pointers to the former object would then point to undefined memory. – dwk 17 hours ago
1  
Absolutely. But there would be nothing stopping you from building a class that manages this behaviour. You could even overload the address-of operator. – Bathsheba 17 hours ago
    
Actually, in most compilers you CAN overwrite vtable pointer which will yield exactly what OP wants. Nice trick to impress your friends, a horrible hack in actual code. – Agent_L 11 hours ago

I would consider regularizing your type.

class Base {
public:
  virtual void whoami() { std::cout << "Base\n"; }
  std::unique_ptr<Base> clone() const {
    return std::make_unique<Base>(*this);
  }
  virtual ~Base() {}
};
class Derived: public Base {
  virtual void whoami() overload {
    std::cout << "Derived\n";
  };
  std::unique_ptr<Base> clone() const override {
    return std::make_unique<Derived>(*this);
  }
public:
  ~Derived() {}
};
struct Base_Value {
private:
  std::unique_ptr<Base> pImpl;
public:
  void whoami () {
    pImpl->whoami();
  }
  template<class T, class...Args>
  void emplace( Args&&...args ) {
    pImpl = std::make_unique<T>(std::forward<Args>(args)...);
  }
  Base_Value()=default;
  Base_Value(Base_Value&&)=default;
  Base_Value& operator=(Base_Value&&)=default;
  Base_Value(Base_Value const&o) {
    if (o.pImpl) pImpl = o.pImpl->clone();
  }
  Base_Value& operator=(Base_Value&& o) {
    auto tmp = std::move(o);
    swap( pImpl, tmp.pImpl );
    return *this;
  }
};

Now a Base_Value is semantically a value-type that behaves polymorphically.

Base_Value object;
object.emplace<Derived>();
object.whoami();

object.emplace<Base>();
object.whoami();

You could wrap a Base_Value instance in a smart pointer, but I wouldn't bother.

share|improve this answer

I suggest you use the Strategy Pattern, e.g.

#include <iostream>

class IAnnouncer {
public:
    virtual ~IAnnouncer() { }
    virtual void whoami() = 0;
};

class AnnouncerA : public IAnnouncer {
public:
    void whoami() override {
        std::cout << "I am A\n";
    }
};

class AnnouncerB : public IAnnouncer {
public:
    void whoami() override {
        std::cout << "I am B\n";
    }
};

class Foo
{
public:
    Foo(IAnnouncer *announcer) : announcer(announcer)
    {
    }
    void run()
    {
        // Do stuff
        if(nullptr != announcer)
        {
            announcer->whoami();
        }
        // Do other stuff
    }
    void expend(IAnnouncer* announcer)
    {
        this->announcer = announcer;
    }
private:
    IAnnouncer *announcer;
};


int main() {
    AnnouncerA a;
    Foo foo(&a);

    foo.run();

    // Ready to "expend"
    AnnouncerB b;
    foo.expend(&b);

    foo.run();

    return 0;
}

This is a very flexible pattern that has at least a few benefits over trying to deal with the issue through inheritance:

  • You can easily change the behavior of Foo later on by implementing a new Announcer
  • Your Announcers (and your Foos) are easily unit tested
  • You can reuse your Announcers elsewhere int he code

I suggest you have a look at the age-old "Composition vs. Inheritance" debate (cf. https://www.thoughtworks.com/insights/blog/composition-vs-inheritance-how-choose)

ps. You've leaked a Derived in your original post! Have a look at std::unique_ptr if it is available.

share|improve this answer

There is a simple error in your program. You assign the objects, but not the pointers:

int main() {
    Base* object = new Derived; //assign a new Derived class instance
    object->whoami(); //this prints "I am Derived"

    Base baseObject;

Now you assign baseObject to *object which overwrites the Derived object with a Base object. However, this does work well because you are overwriting an object of type Derived with an object of type Base. The default assignment operator just assigns all members, which in this case does nothing. The object cannot change its type and still is a Derived objects afterwards. In general, this can leads to serious problems e.g. object slicing.

    *object = baseObject; //reassign existing object to a different type
    object->whoami(); //but it *STILL* prints "I am Derived" (!)

    return 0;
}

If you instead just assign the pointer it will work as expected, but you just have two objects, one of type Derived and one Base, but I think you want some more dynamic behavior. It sounds like you could implement the specialness as a Decorator.

You have a base-class with some operation, and several derived classes that change/modify/extend the base-class behavior of that operation. Since it is based on composition it can be changed dynamically. The trick is to store a base-class reference in the Decorator instances and use that for all other functionality.

class Base {
public:
    virtual void whoami() { 
        std::cout << "I am Base\n"; 
    }

    virtual void otherFunctionality() {}
};

class Derived1 : public Base {
public:
    Derived1(Base* base): m_base(base) {}

    virtual void whoami() override {
        std::cout << "I am Derived\n";

        // maybe even call the base-class implementation
        // if you just want to add something
    }

    virtual void otherFunctionality() {
        base->otherFunctionality();
    }
private:
    Base* m_base;
};

Base* object;

int main() {
    Base baseObject;
    object = new Derived(&baseObject); //assign a new Derived class instance
    object->whoami(); //this prints "I am Derived"

    // undecorate
    delete object;
    object = &baseObject; 

    object->whoami(); 

    return 0;
}

There are alternative patterns like Strategy which implement different use cases resp. solve different problems. It would probably good to read the pattern documentation with special focus to the Intent and Motivation sections.

share|improve this answer

I'm open to destroying the old object and creating a new one, as long as I can create the new object at the same memory address, so existing pointers aren't broken.

The C++ Standard explicitly addresses this idea in section 3.8 (Object Lifetime):

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object <snip>

Oh wow, this is exactly what you wanted. But I didn't show the whole rule. Here's the rest:

if:

  • the storage for the new object exactly overlays the storage location which the original object occupied, and
  • the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
  • the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
  • the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).

So your idea has been thought of by the language committee and specifically made illegal, including the sneaky workaround that "I have a base class subobject of the right type, I'll just make a new object in its place" which the last bullet point stops in its tracks.

You can replace an object with an object of a different type as @RossRidge's answer shows. Or you can replace an object and keep using pointers that existed before the replacement. But you cannot do both together.

However, like the famous quote: "Any problem in computer science can be solved by adding a layer of indirection" and that is true here too.

Instead of your suggested method

Derived d;
Base* p = &d;
new (p) Base();  // makes p invalid!  Plus problems when d's destructor is automatically called

You can do:

unique_ptr<Base> p = make_unique<Derived>();
p.reset(make_unique<Base>());

If you hide this pointer and slight-of-hand inside another class, you'll have the "design pattern" such as State or Strategy mentioned in other answers. But they all rely on one extra level of indirection.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.