Can I get polymorphic behavior without using virtual functions?

后端 未结 11 1357
栀梦
栀梦 2020-12-03 13:54

Because of my device I can\'t use virtual functions. Suppose I have:

class Base
{
    void doSomething() { }
};

class Derived : public Base
{
    void doSom         


        
11条回答
  •  离开以前
    2020-12-03 14:39

    Sure you can do this; it's just not necessarily easy.

    If there is a finite list of derived classes and you know what they are when you define the base class, you can do this using a non-polymorphic member function wrapper. Here is an example with two derived classes. It uses no standard library facilities and relies solely on standard C++ features.

    class Base;
    class Derived1;
    class Derived2;
    
    class MemFnWrapper
    {
    public:
    
        enum DerivedType { BaseType, Derived1Type, Derived2Type };
    
        typedef void(Base::*BaseFnType)();
        typedef void(Derived1::*Derived1FnType)();
        typedef void(Derived2::*Derived2FnType)();
    
        MemFnWrapper(BaseFnType fn) : type_(BaseType) { fn_.baseFn_ = fn; }
        MemFnWrapper(Derived1FnType fn) : type_(Derived1Type) {fn_.derived1Fn_ = fn;}
        MemFnWrapper(Derived2FnType fn) : type_(Derived2Type) {fn_.derived2Fn_ = fn;}
    
        void operator()(Base* ptr) const;
    
    private:
    
        union FnUnion
        {
            BaseFnType baseFn_;
            Derived1FnType derived1Fn_;
            Derived2FnType derived2Fn_;
        };
    
        DerivedType type_;
        FnUnion fn_;
    };
    
    class Base
    {
    public:
    
        Base() : doSomethingImpl(&Base::myDoSomething) { }
        Base(MemFnWrapper::Derived1FnType f) : doSomethingImpl(f) { }
        Base(MemFnWrapper::Derived2FnType f) : doSomethingImpl(f) { }
    
        void doSomething() { doSomethingImpl(this); }
    private:
        void myDoSomething() { }
        MemFnWrapper doSomethingImpl;
    };
    
    class Derived1 : public Base
    {
    public:
        Derived1() : Base(&Derived1::myDoSomething) { }
    private:
        void myDoSomething() { } 
    };
    
    class Derived2 : public Base
    {
    public:
        Derived2() : Base(&Derived2::myDoSomething) { }
    private:
        void myDoSomething() { } 
    };
    
    // Complete the MemFnWrapper function call operator; this has to be after the
    // definitions of Derived1 and Derived2 so the cast is valid:
    void MemFnWrapper::operator()(Base* ptr) const
    {
        switch (type_)
        {
        case BaseType:     return (ptr->*(fn_.baseFn_))();
        case Derived1Type: return (static_cast(ptr)->*(fn_.derived1Fn_))();
        case Derived2Type: return (static_cast(ptr)->*(fn_.derived2Fn_))();
        }
    }
    
    int main()
    {
        Base* obj0 = new Base;
        Base* obj1 = new Derived1;
        Base* obj2 = new Derived2;
        obj0->doSomething(); // calls Base::myDoSomething()
        obj1->doSomething(); // calls Derived1::myDoSomething()
        obj2->doSomething(); // calls Derived2::myDoSomething()
    }
    

    (I originally suggested using std::function, which does a lot of this work for you, but then I remembered it is a polymorphic function wrapper, so it necessarily uses virtual functions. :-P Oops. You can view the revision history to see what that one looked like)

提交回复
热议问题