4

我有这两个类:

class   IBaseA
{
public:
  virtual bool  sayHello(std::string&) = 0;
  ~IBaseA(){}
};                                                                                                   

class   BaseA: public IBaseA
{
public:
  virtual bool  sayHello(std::string &str)
  {
    std::cout << "Hello " << str << std::endl;
    return (true);
  }
  BaseA(){}

};

你能解释一下为什么我不能做那样的事情吗

bool  (IBaseA::*ptr)(std::string&) = &BaseA::sayHello;

错误:无法将 'bool (BaseA:: )(std::string&) {aka bool (BaseA:: )(std::basic_string&)}' 转换为 'bool (IBaseA:: )(std::string&) {aka bool (IBaseA:: )(std::basic_string&)}' 初始化

我不明白为什么我不能做这样的事情。

但是,如果我将作业更改为

bool  (IBaseA::*ptr)(std::string&) = &IBaseA::sayHello;

那么我可以毫无问题地使用这个指针

BaseA A;
(A.*ptr)(str);

编辑:感谢您的回答,我在想,由于所有地址都在 vtable 中,根据我从维基百科的理解,它们是相同的位置。

4

4 回答 4

5

指针到成员的转换与正常的指针转换相反。您可以将指向派生类的指针转换为指向基类的指针,但反之则不行。您可以将指向基类成员的指针转换为指向派生类成员的指针,反之则不行。

始终考虑转换是否有效。

普通指针: 的所有实例BaseA都是 的实例IBaseA,因此转换是合法的。并非所有IBaseA实例都是BaseA实例,因此您无法以其他方式转换。

指向成员的指针: 的所有成员IBaseA也存在于 中BaseA,因此您可以将指向成员的指针转换为指向成员的IBaseA指针BaseA。但是,并非 的所有成员BaseA都存在于IBaseA中,因此无法进行相反的转换。

于 2013-06-21T12:41:59.797 回答
1

虽然它可能看起来违反直觉,但您不能将派生类型的指向成员的指针转换为指向基类的成员的指针。正确的转换是相反的:您可以将指向成员的指针转换为基数到指向成员的指针到派生。

原因是,如果基类有,则派生类型保证具有该成员,但反之则不正确(即指向派生类型的成员指针可以引用已添加但不存在的成员在基地)。

您可能缺少的另一件事是指向成员的函数是多态的,也就是说,您可以存储并且如果应用它的成员是 type &IBase::sayHello,它将调用。Base::sayHelloBase

于 2013-06-21T12:48:28.560 回答
1

给定两个指向成员的类型T C1::*P1T C2::*P2(其中 T 可能是函数类型),如果 C2 派生自 C1,则只能将 P1 转换为 P2。请注意,这是指向对象的指针的倒数,您只能向上转换。

原因是,如果你有一个指向基类成员的指针,那么任何子类都保证有这个成员,因为它继承了它。反之则不适用。

这是基本的类型转换规则。它不会仅仅因为您在那里使用的特定指针恰好是基类中存在的虚函数的覆盖而改变。

于 2013-06-21T12:42:21.833 回答
1

真正的答案可能是“因为语言规范说你不能”,但是,想想你想要做什么:

bool  (IBaseA::*ptr)(std::string&) = &BaseA::sayHello;

本质上,这读作:我想要一个名为 ptr 的变量,它是指向 IBaseA 的成员函数的指针,并且我希望它指向 BaseA 中的方法 'sayHello'。

是的,BaseA 中的 sayHello 方法覆盖了 IBaseA 中的方法,但它们仍然是不同的方法。想象一下,如果您尝试使用指针调用实际上不是 BaseA 的 IBaseA 类型的对象上的方法-这在语法上是允许的,但您希望会发生什么?

换句话说,通过获取指向派生类成员的指针并将其分配给声明为指向基类成员的变量,您将破坏静态类型安全。

于 2013-06-21T12:45:37.407 回答