简体   繁体   English

覆盖指向成员函数的指针

[英]Override pointer-to-member-function

I have these two classes: 我有这两个类:

class A {
public:
    A() { m_ptr = NULL; }
    void (*m_ptr)();
    void a() { if (m_ptr) m_ptr(); }
};

class B : public A {
public:
    B() { m_ptr = b; }
    void b() {
        std::cout << "B::b() is called" << std::endl;
    }
};

And I want to use them like this: 我想像这样使用它们:

B b;
b.a();

and get the following to be called B::b() . 并获得以下称为B::b()

Of course this is not being compiled as B::b is not of type void(*)() . 当然,这不是编译为B::b不是void(*)()

How can I make it work? 我怎样才能使它工作?

UPDATE. UPDATE。 To whom who asks "why?" 谁问“为什么?” and "what for?". 和“为什么?”。
The class A is a very basic class which has many successors in production code. A类是一个非常基础的类,在生产代码中有许多后继者。 The class B is 6-th successor and I want to extend A (the most convinient place) to call there one more method (from B) which can be present and may be not in another successors af A and B. B级是第6个继任者,我想扩展A(最方便的地方)再召集一个方法(来自B),这个方法可以存在,也可能不在A和B的另一个后继者中。
A virtual method with empty body can be employed for that but it is ugly and I want to avoid it. 可以使用具有空体的虚拟方法,但它很难看,我想避免它。 Abstract method even more so (because of existing derived successors code). 抽象方法更是如此(因为现有的派生后继代码)。
I don't want to use external function of type void (*)() to not loose access to internal data of all hierarchy. 我不想使用void(*)()类型的外部函数来放松对所有层次结构的内部数据的访问。

You can't make it work as your classes are defined now. 您现在无法定义类,因此无法使其正常工作。

Calling a non-static member function of another class requires an instance of that class. 调用另一个类的非静态成员函数需要该类的实例。 You either need to store a reference to the object that owns the member function when storing the function pointer, or pass a reference to the object when you make the call to A::a . 您需要在存储函数指针时存储对拥有成员函数的对象的引用,或者在调用A::a时传递对该对象的引用。

You also need to declare m_ptr with the type void (B::*)() , which is pointer to member of B that is a function taking no parameters and returning void . 您还需要使用void (B::*)()类型声明m_ptr ,它是指向B成员的指针,该函数不带参数并返回void

Look at this example: 看看这个例子:

class A {
public:
    A() { m_ptr = nullptr; }
    void a(B& b) { if (m_ptr) (b.*m_ptr)(); } // Now takes reference to B object.
    void (B::*m_ptr)();                       // Pointer to member function of B.
};

class B : public A {
public:
    B() { m_ptr = &B::b; } // Adress of qualified function.
    void b() {
        std::cout << "B::b() is called" << std::endl;
    }
};

Now we can call B::b like this: 现在我们可以这样调用B::b

B b;
b.a(b); // Pass reference to b when calling.

Your use of inheritence in this way is confusing as it implies that the real problem you are trying to solve is to invoka a member of a derived class through the base class. 以这种方式使用继承是令人困惑的,因为它意味着您要解决的真正问题是通过基类调用派生类的成员。 This is usually accomplished using a simple virtual function like this: 这通常使用这样的简单虚函数来完成:

class A {
public:
    virtual ~A() {}
    void a() const { b(); } // Call b.
private:
    virtual void b() const {}
};

class B : public A {
public:
    virtual void b() const override { // C++11 override specifier (optional).
        std::cout << "B::b() is called" << std::endl;
    }
};

And used like this: 像这样使用:

B b;
b.a(); // B::b is called.

Well, probably not the purpose of this exercise, but you can simply declare static void b() if you want to make it work. 好吧,可能不是本练习的目的,但如果你想让它工作,你可以简单地声明static void b()

Another option is to declare friend void b() , but then the "B::b() is called" printout would be stating a wrong fact. 另一个选择是声明friend void b() ,但是然后"B::b() is called" printout会说明错误的事实。

I would suggest using CRTP since you want to avoid virtual mechanism. 我建议使用CRTP,因为你想避免虚拟机制。 Note, however, your code might require some design changes to accommodate this pattern. 但请注意,您的代码可能需要进行一些设计更改才能适应此模式。 But it does provide type safety and has no run-time overhead. 但它确实提供了类型安全性并且没有运行时开销。 Hope it helps. 希望能帮助到你。

Code on ideone.com : ideone.com上的代码

#include <iostream>
#include <type_traits>

namespace so {

class B;

template<typename T>
class A {
 public:
  template<typename U = T, typename = typename std::enable_if<std::is_same<U, B>::value>::type>
  void foo_A() {
   std::cout << "foo_A : ";
   static_cast<U *>(this)->foo_B();
  }
};

class B: public A<B> {
 public:
  void foo_B() {
   std::cout << "foo_B" << std::endl;
  }
};

class C: public A<C> {
 public:
  void foo_C() {
   std::cout << "foo_C" << std::endl;
  }
};
} // namespace so

int main() {
 so::B b_;
 so::C c_;

 b_.foo_A();
 b_.foo_B();

 //c_.foo_A(); Compile error: A<C>::foo_A() does not exist!
 c_.foo_C();

 return (0);
}

Program output: 节目输出:

foo_A : foo_B
foo_B
foo_C

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM