无法从继承的类中分配指向方法的指针

时间:2013-06-21 12:35:08

标签: c++

我有这两节课:

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&amp;){又名bool   (BaseA :: )(std :: basic_string&amp;)}'到'bool   (IBaseA :: )(std :: string&amp;){又名bool   初始化中的(IBaseA :: )(std :: basic_string&amp;)}'

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

但如果我将作业更改为

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

然后我可以毫无问题地使用这个指针

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

编辑: 谢谢你的回答,我在想,因为所有地址都在vtable中,所以根据我对维基百科的理解,它们是相同的位置。

4 个答案:

答案 0 :(得分:5)

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

始终考虑转换是否有效。

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

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

答案 1 :(得分:1)

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

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

这是基本类型转换规则。它不会因为你所在的特定指针恰好是对基类中存在的虚函数的覆盖而改变。

答案 2 :(得分:1)

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

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

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

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

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

答案 3 :(得分:1)

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

原因是如果基类具有派生类型,则保证派生类型具有该成员,但是相反的方式不是真的(即派生类型的指向成员的指针可以引用< em>添加而不存在于基础中。

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