Ways to detect whether a C++ virtual function has been redefined in a derived class

前端 未结 9 1312
不知归路
不知归路 2020-12-01 14:10

In brief: From a C++ base-class pointer which points to an instance of a derived class, how can one determine at run-time whether a non-pure virtual functio

相关标签:
9条回答
  • 2020-12-01 14:12

    I don't know how to do such detection, but did you consider use of static polymorphism instead? Optimizations can be done at compile-time if every virtual method of Equation is replaced with a template "policy" with default value.

    //default implementation of a virtual method turned into a functor
    //which optionally takes a reference to equation
    class DefaultFunctor1
    {
    public:
        //...
        double operator()(double x) { return log(x); }
    };
    template<class F1 = DefaultFunctor1>
    class Equation
    {
    public:
        typedef F1 Functor1;
        //...
    private:
        F1 f1;
    };
    class Solver
    {
    public:
        //....
        template<class Equation>
        void solve(Equation& eq)
        {
            Loki::Int2Type<
                            Loki::IsSameType<Equation::Functor1, DefaultFunctor1>::value
                           > selector;
            //choose at compile time appropriate implementation among overloads of doSolve
            doSolve(selector);
        }
    private:
        //.... overloads of doSolve here
    };
    int main()
    {
        Equation<> eq;
        Solver solver;
        solver.solve(eq); //calls optimized version
        Equation<MyFunctor> my_eq;
        solver.solve(my_eq); //calls generic version
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-01 14:18

    Perhaps this helps. It alone doesn't answer your original question, but you can augment your base class (here, Foo) to use a certain interface if it is supplied or use a default method otherwise.

    #include <iostream>
    
    struct X {
        virtual void x () = 0;
    };
    
    struct Y {
        virtual void y () = 0;
    };
    
    
    struct Foo {
        virtual ~ Foo () {}
    
        bool does_x () {
            return NULL != dynamic_cast <X*> (this);
        }
    
        bool does_y () {
            return NULL != dynamic_cast <Y*> (this);
        }
    
        void do_x () {
            dynamic_cast <X&> (*this) .x ();
        }
    
        void do_y () {
            dynamic_cast <Y&> (*this) .y ();
        }
    };
    
    struct foo_x : public Foo, public X {
        void x () {
            std :: cout << __PRETTY_FUNCTION__ << std :: endl;
        }
    };
    
    
    struct foo_y : public Foo, public Y {
        void y () {
            std :: cout << __PRETTY_FUNCTION__ << std :: endl;
        }
    };
    
    struct foo_xy : public Foo, public X, public Y {
        void x () {
            std :: cout << __PRETTY_FUNCTION__ << std :: endl;
        }
    
        void y () {
            std :: cout << __PRETTY_FUNCTION__ << std :: endl;
        }
    };
    
    void test (Foo & f)
    {
        std :: cout << &f << " "
            << "{"
            << "X:" << f .does_x () << ", "
            << "Y:" << f .does_y ()
            << "}\n";
    
        if (f .does_x ())
            f .do_x ();
    
        if (f .does_y ())
            f .do_y ();
    }
    
    int main ()
    {
        foo_x x;
        foo_y y;
        foo_xy xy;
        test (x);
        test (y);
        test (xy);
    }
    
    0 讨论(0)
  • 2020-12-01 14:21

    What about getting pointer to the base-class function on the first use and compare it with actual one

       class Base { virtual int foo(); }
       class Derived : public Base { virtual int foo(); }
    
       bool Xxx::checkOverride()
       {
           int (Base::*fpA)();
           int (Base::*fpb)();
    
           fpA = &Base::foo;
           fpB = &Derived::foo;
    
           return (fpA != fpB);
       }
    
    0 讨论(0)
  • 2020-12-01 14:27

    Even though this probably is somehow possible, I would advice not doing it. You are:

    • Violating the OOP principles. If you are given a general class/interface, you should not check for implementation details. This increases dependency between classes and is exactly the opposite of what OOP was designed for.
    • Duplicating code. Considering that you use the constants that would be otherwise returned by the Equation class.
    • Obfuscating code. Many conditions with type checks will make your program look ugly.
    • Probably doing a premature optimization. There is almost no speed difference between executing a virtual function call and a condition. Have you run your profiler to check if it's the virtual functions that are the bottleneck? It is almost never the case in a well designed application/library.
    0 讨论(0)
  • 2020-12-01 14:30

    After only finding results that link to gcc's PMF extension, I thought there must be a proper way to do so.

    I found a solution without any hacks and is at least tested to work on gcc & llvm:

    #include <iostream>
    #include <typeinfo>
    
    struct A { virtual void Foo() {} };
    struct B : public A { void Foo() {} };
    struct C : public A { };
    
    int main() {
        std::cout << int(typeid(&A::Foo) == typeid(&A::Foo)) << std::endl;
        std::cout << int(typeid(&A::Foo) == typeid(&B::Foo)) << std::endl;
        std::cout << int(typeid(&A::Foo) == typeid(&C::Foo)) << std::endl;
        return 0;
    }
    

    http://ideone.com/xcQOT6

    PS: I actually use it in a CEventClient system. So you derive your class from CEventClient and if it overrides an event method it will automatically 'link' the event.

    0 讨论(0)
  • 2020-12-01 14:32

    For future reference, it turns out that GCC provides this extension: http://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html which allows checking if a method was overridden with

    (void*)(obj.*(&Interface::method)) != (void*)(&Interface::method)
    

    ICC supports this extension officially, clang's docs don't mention it but the code works and even compiles without the warning.

    MSVC doesn't support this, though, so there's that.

    Also, it appears to not work with methods defined in the header (i.e. inline) in a separate library if you link to a different version of the library where the implementation has changed. If I interpret the standard correctly, this is undefined behaviour (changing the implementation that is) but if the implementation stays the same, then the address should be unique too. So don't do that with inline methods.

    0 讨论(0)
提交回复
热议问题