在父类中实现抽象类成员 < > >可以在C++中使用继承自另一父类的成员来实现抽象基类吗?< /强>

在父类中实现抽象类成员 < > >可以在C++中使用继承自另一父类的成员来实现抽象基类吗?< /强> ,c++,inheritance,abstract-class,C++,Inheritance,Abstract Class,它在C#中工作,所以我试着用C++: // Virtual destructors omitted for brevity class ITalk { public: virtual void SayHi() = 0; }; class Parent { public: void SayHi(); }; class Child : public Parent, public ITalk { }; void Parent::SayHi() { std::printf

它在C#中工作,所以我试着用C++:

// Virtual destructors omitted for brevity

class ITalk
{
public:
    virtual void SayHi() = 0;
};

class Parent
{
public:
    void SayHi();
};

class Child : public Parent, public ITalk
{
};

void Parent::SayHi()
{
    std::printf("Hi\n");
}
但我的编译器并不喜欢它:

ITalk* lChild = new Child(); // You idiot, Child is an abstract class!
lChild->SayHi();

我无法将
public-ITalk
添加到
Parent
类,因为“基类'ITalk'已经是'Parent'的基类。”我可以将
public-ITalk
移动到
Parent
类,但在我的特定场景中,这会使很多事情变得复杂。

ITalk
包含纯虚拟函数
SayHi()
,因此如果您希望能够实例化从
ITalk
派生的类,那么该类必须实现
SayHi()

如果您不这样做,下面将生成未定义的行为

ITalk* lChild = new Child();
lChild->SayHi();
delete lChild;

不,因为你真正拥有的是两个基类,彼此都不了解

Italk Parent / \ / \ | | +---------+ | Child 还有Italk的SayHi:

lChild->ITalk::SayHi(); 
后者是纯虚拟的,因为它的抽象需要在Child中本地重写。要满足这一点,您需要定义

Child::SayHi();
调用SayHi时,它现在将隐藏Parent::SayHi(),而不将其范围限定到类:

lChild->SayHi() //parent's now hidden, invoke child's
当然,Child::SayHi()可以调用Parent::SayHi():


这将解决您的问题。

尝试使用虚拟继承

class ITalk
{
public:
  virtual void SayHi() = 0;
};

class Parent: virtual ITalk
{
public:
   void SayHi();
};

class Child : public Parent, public virtual ITalk
{
};

void Parent::SayHi()
{
    std::printf("Hi\n");
}

这不可能像你写的那样完成。其背后的原因是,每个非静态方法都需要对象(
this
)来操作(这里您不使用对象的任何字段或方法,但这并不重要),并且该对象必须是适当的类型
Parent::sayHi
期望
this
属于
Parent
类型,并且由于
ITalk
Parent
根本不相关,
Parent::sayHi
ITalk::sayHi
方法基本上是不兼容的

C++具有静态类型系统,因此必须在编译时知道类型。使用动态类型的语言通常对这种结构不太严格,因为它们可以在函数调用时测试对象是否属于适当的类

<>在C++中,实现这种行为的最简单的方法是简单地制作<代码>子::SayHi/Cux>调用<代码>父::SayHi/Cuth>,因为子是唯一知道“<代码>父/代码>和<代码> ITALK >的类,它们应该如何关联。
class Child : public Parent, public ITalk
{
    virtual void sayHi(){ Parent::sayHi(); }
};

所以不
子类
无法继承它要用于实现
ITalk
?@emddudley Yep的成员,无法继承。DougT.解释了为什么这会使编译器更清楚地看到函数。如果说编译器在查找
ITalk::SayHi()
的重写实现时只查看本地类,而不搜索继承树,这是否正确?是的。当实例化一个对象时,编译器会根据您正在实例化的对象进行查找,并确保它正上方的任何纯虚拟对象都已在本地实例化。
lChild->SayHi() //parent's now hidden, invoke child's
void Child::SayHi()
{
     Parent::SayHi();
}
class ITalk
{
public:
  virtual void SayHi() = 0;
};

class Parent: virtual ITalk
{
public:
   void SayHi();
};

class Child : public Parent, public virtual ITalk
{
};

void Parent::SayHi()
{
    std::printf("Hi\n");
}
class Child : public Parent, public ITalk
{
    virtual void sayHi(){ Parent::sayHi(); }
};