从c++中的派生类调用未在基类上定义的成员函数是否安全

is it safe to calling a member function not defined on the base class from of a derived class in c++?

本文关键字:定义 成员 函数 是否 基类 安全 c++ 派生 调用      更新时间:2023-10-16

我读到了关于委派的文章,我希望能够在基类中调用任何函数作为参数传递,具体取决于事件,因此,如果例如我有一个解析器对象,并且我希望根据找到的令牌从另一个对象分配要调用的方法。我按照下面的方式做了,它有效,但我不确定它是正确的方式还是便携的。

class base{
 public: 
     typedef void (base::*methodPTR)();
     methodPTR pfn;
    void setMethod(methodPTR fn)
    {
        pfn = fn;
    }
    void run(){
        if(pfn) (this->*pfn)();
    }
};
class a : public base {
 public:
};
class b : public base
{
    a ob;
 public:
     void init()
     {
             //this function fn is not define neither in object "a" or "base"
             //but still I can assign arbitrary member function just like I wanted
         ob.setMethod(static_cast<base::methodPTR>(&b::fn));
     }
     void fn()
     {
         cout << "from class b!" << endl;
     }
     void test()
     {
         ob.run();
     }
};
int _tmain(int argc, _TCHAR* argv[])
{
    b x;
    x.init();
    x.test();
    return 0;
}

只要你确信你从未在一个对象上调用成员指针,而该对象实际上不是指针来源的类型之一(即你没有在base上调用a::x),那么你正在做的事情是安全的。

尝试这个问题的模板解决方案,在这个例子中,我确信使用正确的对象来调用正确的函数。我们可以在有映射对象和回调的情况下使用它,并且可能会根据某些条件调用它们。

   //store objects vs callbacks
   //you could replace int in map with some condition or key to invoke a callback
#include <iostream>
#include <map>
using namespace std;
template<class T>
class A {
  protected:
  void (T::*curr_f)();
  private:
  static std::map<int, std::map<T*,void (T::*)() > > callBacks;
  public:
  virtual void set(void (T::*f)()) {
    curr_f = f;
    cout<<"Set in A"<<endl;
    T* obj = new T();
    static int x = 0;
    callBacks[++x][obj] = f;
    //      (obj->*curr_f)();
  }
  virtual void new_function() {cout<<"in A"<<endl;};
  static void run()
  {
    for(typename std::map<int,std::map<T*,void (T::*)() > >::iterator itr = A<T>::callBacks.begin();
        itr != A<T>::callBacks.end(); ++itr)
    {
      for(typename std::map<T*,void (T::*)() >::iterator itr2 = itr->second.begin();
          itr2 != itr->second.end(); ++itr2)
      {
        ((itr2->first)->*(itr2->second))();
      }
    }
  }
};
template<class T>
std::map<int, std::map<T*,void (T::*)() > > A<T>::callBacks;
class B :public A<B> {
  public:
    void func() {
      set(&B::new_function);
    };
    void new_function() {cout<<"in B"<<endl;};
};
class C:public A<C> {
  public:
    void func() {
      set(&C::new_function);
    };
    void new_function() {cout<<"in C"<<endl;};
};
int main()
{
  B obj1;
  C obj2;
  obj1.func();
  obj2.func();
  A<B>::run();
  A<C>::run();
}