How can I create a polymorphic object on the stack?

前端 未结 12 1756
谎友^
谎友^ 2021-01-12 05:40

How do I allocate a polymorphic object on the stack? I\'m trying to do something similar to (trying to avoid heap allocation with new)?:

A* a = NULL;

switch         


        
12条回答
  •  死守一世寂寞
    2021-01-12 06:19

    Run this short program and you'll see why polymorphic objects do not work on the stack very well. When you create a stack object of a derived type that is unknown and expect it to be returned from a function call, what happens is the object is destroyed when that calling function goes out of scope. Thus the object only lives as long as that function is within scope. In order to return a valid object that will outlive the calling function you need to use the heap. This is demonstrated with this simple hierarchy and two versions of the same function with a switch statement except one does the stack and the other does it on the heap. Look at the output from both implementations and look to see what methods are called, what class they are being called from and when they are being called.

    #include 
    #include 
    
    class Base {
    public:
        enum Type {
            DERIVED_A = 0,
            DERIVED_B,
            DERIVED_C
        };
    
    protected:
        Type type_;
    
    public:
        explicit Base(Type type) : type_(type) {
            std::cout << "Base Constructor Called." << std::endl;
        }
        virtual ~Base() {
            std::cout << "Base Destructor Called." << std::endl;
        }
    
        virtual void doSomething() {
            std::cout << "This should be overridden by derived class without making this a purely virtual method." << std::endl;
        }
    
        Type getType() const { return type_; }
    };
    
    class DerivedA : public Base {
    public:
        DerivedA() : Base(DERIVED_A) {
            std::cout << "DerivedA Constructor Called." << std::endl;
        }
        virtual ~DerivedA() {
            std::cout << "DerivedA Destructor Called." << std::endl;
        }
    
        void doSomething() override {
            std::cout << "DerivedA overridden this function." << std::endl;
        }
    };
    
    class DerivedB : public Base {
    public:
        DerivedB() : Base(DERIVED_B) {
            std::cout << "DerivedB Constructor Called." << std::endl;
        }
        virtual ~DerivedB() {
            std::cout << "DerivedB Destructor Called." << std::endl;
        }
    
        void doSomething() override {
            std::cout << "DerivedB overridden this function." << std::endl;
        }
    };
    
    class DerivedC : public Base {
    public:
        DerivedC() : Base(DERIVED_C) {
            std::cout << "DerivedC Constructor Called." << std::endl;
        }
        virtual ~DerivedC() {
            std::cout << "DerivedC Destructor Called." << std::endl;
        }
    
        void doSomething() override {
            std::cout << "DerivedC overridden this function." << std::endl;
        }
    };    
    
    Base* someFuncOnStack(Base::Type type) {
        Base* pBase = nullptr;
    
        switch (type) {
            case Base::DERIVED_A: {
                DerivedA a;
                pBase = dynamic_cast(&a);
                break;
            }
            case Base::DERIVED_B: {
                DerivedB b;
                pBase = dynamic_cast(&b);
                break;
            }
            case Base::DERIVED_C: {
                DerivedC c;
                pBase = dynamic_cast(&c);
                break;
            }
            default: {
                pBase = nullptr;
                break;
            }
        }
        return pBase;
    }
    
    Base* someFuncOnHeap(Base::Type type) {
        Base* pBase = nullptr;
    
        switch (type) {
            case Base::DERIVED_A: {
            DerivedA* pA = new DerivedA();
            pBase = dynamic_cast(pA);
            break;
            }
            case Base::DERIVED_B: {
            DerivedB* pB = new DerivedB();
            pBase = dynamic_cast(pB);
            break;
            }
            case Base::DERIVED_C: {
            DerivedC* pC = new DerivedC();
            pBase = dynamic_cast(pC);
            break;
            }
            default: {
            pBase = nullptr;
            break;
            }
        }
        return pBase;    
    }
    
    int main() {
    
        // Function With Stack Behavior
        std::cout << "Stack Version:\n";
        Base* pBase = nullptr;
        pBase = someFuncOnStack(Base::DERIVED_B);
        // Since the above function went out of scope the classes are on the stack
        pBase->doSomething(); // Still Calls Base Class's doSomething
        // If you need these classes to outlive the function from which they are in
        // you will need to use heap allocation.
    
        // Reset Base*
        pBase = nullptr;
    
        // Function With Heap Behavior
        std::cout << "\nHeap Version:\n";
        pBase = someFuncOnHeap(Base::DERIVED_C);
        pBase->doSomething();
    
        // Don't Forget to Delete this pointer
        delete pBase;
        pBase = nullptr;        
    
        char c;
        std::cout << "\nPress any key to quit.\n";
        std::cin >> c;
        return 0;
    }
    

    Output:

    Stack Version:
    Base Constructor Called.
    DerivedB Constructor Called.
    DerivedB Destructor Called.
    Base Destructor Called.
    This should be overridden by derived class without making this a purely virtual method.
    
    Heap Version:
    Base Constructor Called.
    DerivedC Constructor Called.
    DerivedC overridden this function.
    DerivedC Destructor called.
    Base Destructor Called. 
    

    I'm not saying that it can not be done; I'm just stating the caveats in trying to do so. It may be ill-advised to try to do something of the sort. I do not know of any way to do this unless if you have a wrapper class that will contain the stack allocated objects to manage their life time. I'll have to try and work on that to see if I can come up with something of the sort.

提交回复
热议问题