Is it possible to change a C++ object's class after instantiation?

后端 未结 16 2151
忘掉有多难
忘掉有多难 2021-02-02 06:50

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 eac

16条回答
  •  [愿得一人]
    2021-02-02 06:54

    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.

提交回复
热议问题