C++ 为什么C++;不允许基类实现派生类';继承接口?

C++ 为什么C++;不允许基类实现派生类';继承接口?,c++,class,inheritance,interface,C++,Class,Inheritance,Interface,这就是我要说的 // some guy wrote this, used as a Policy with templates struct MyWriter { void write(std::vector<char> const& data) { // ... } }; MyOwnClass是根据MyWriter实现的。为什么MyOwnClass继承的成员函数不能自动实现IWriter的接口?相反,用户必须编写只调用基类版本的转发函数,如中所示 clas

这就是我要说的

// some guy wrote this, used as a Policy with templates
struct MyWriter {
  void write(std::vector<char> const& data) {
    // ...
  }
};
MyOwnClass是根据MyWriter实现的。为什么MyOwnClass继承的成员函数不能自动实现IWriter的接口?相反,用户必须编写只调用基类版本的转发函数,如中所示

class MyOwnClass: private MyWriter, public IWriter {
public:
  void write(std::vector<char> const& data) {
    MyWriter::write(data);
  }
};
class MyOwnClass:private MyWriter,public IWriter{
公众:
无效写入(标准::向量常量和数据){
MyWriter::写入(数据);
}
};
我知道,在Java中,如果有一个类实现了一个接口,并且派生自一个碰巧有合适方法的类,那么这个基类会自动实现派生类的接口


<>为什么C++不这么做?这似乎是很自然的事情。

这是多重继承,有两个继承的函数具有相同的签名,它们都有实现。这就是C++与java不同的地方。 因此,对静态类型为
MyBigClass
的表达式调用
write
,对于所需的继承函数是不明确的

如果只通过基类指针调用
write
,则不需要在派生类中定义
write
,这与问题中的主张相反。现在,问题变成了包含一个纯说明符,在派生类中实现该函数对于使类具体化和实例化是必要的

MyWriter::write
不能用于
MyBigClass
的虚拟调用机制,因为虚拟调用机制需要一个接受隐式
IWriter*const this
的函数,而
MyWriter::write
接受隐式
MyWriter*const this
。需要一个新函数,该函数必须考虑
IWriter
子对象和
MyWriter
子对象之间的地址差异

从理论上讲,编译器可以自动创建这个新函数,但它是脆弱的,因为基类中的更改可能会突然导致选择一个新函数进行转发。在java中,它不太脆弱,只有单一继承是可能的(只有一个选项才能选择什么功能),C++支持完整的多重继承,选择是不明确的,我们甚至还没有开始继承或继承虚拟继承。
实际上,虚拟继承解决了这个问题(子对象地址之间的差异)。但它需要额外的开销,这不是必要的大部分时间,而C++的指导原则是“你不为你不使用的东西付费”。

< P>只是让我的作者从IWriter派生,消除MyOwnClass的I作家派生,继续生活。这应该可以解决问题,并且不会干扰模板代码

<>为什么C++不这样做?< /P> 我不知道你在问什么。可以重写C++来允许这个吗?是的,但目的是什么

<>因为<代码> MyWriter < /C>和<代码> IWriter < /C>是完全不同的类,在C++中通过“代码> IWriter < /COD>”的实例调用“代码> MyWriter < /COD>的成员是非法的。成员指针具有完全不同的类型。正如一个
MyWriter*
不能转换为
IWriter*
,一个
void(MyWriter::*)(const std::vector&)
也不能转换为
void(IWriter::*)(const std::vector&)

< C++的规则不会改变,因为可能有第三个类组合了这两个类。两个类都不是彼此的直接父/子关系。因此,它们被视为完全不同的类

请记住:成员函数始终使用一个附加参数:指向它们所指向对象的
指针。不能在
IWriter*
上调用
void(MyWriter::*)(const std::vector&)
。第三个类可以有一个将自己强制转换为适当基类的方法,但它实际上必须有这个方法。因此,您或C++编译器都必须创建它。C++的规则要求这个。

考虑在没有派生类方法的情况下,要使这项工作正常,必须发生什么

函数获取一个
IWriter*
。用户调用它的
write
成员,只使用
IWriter*
指针。所以编译器究竟如何生成要调用的代码
MyWriter::writer
?请记住:
MyWriter::writer
需要一个
MyWriter
实例。而且
IWriter
MyWriter
之间没有关系

那么编译器如何在本地执行类型强制呢?编译器必须检查虚拟函数,以查看要调用的实际函数是否采用
IWriter
或其他类型。如果它采用另一种类型,则必须将指针转换为其真实类型,然后再转换为虚函数所需的类型。在完成所有这些之后,它将能够拨打电话

所有这些开销都会影响每个虚拟呼叫。所有人都必须至少检查一下是否要调用实际函数。为了以防万一,每个调用还必须生成代码来进行类型转换

每个虚拟函数调用都有一个“get类型”和条件分支。即使永远不可能触发该分支。所以,不管你是否使用它,你都要为它付费。这不是C++方式。< /P> 更糟糕的是,虚拟调用的直接v表实现不再可能。执行虚拟分派的最快方法不是一致性实现。C++委员会是“强>不<强”,将做出任何可能导致这种实现不可能的改变。

A
class MyOwnClass: private MyWriter, public IWriter {
  // other stuff
};
class MyOwnClass: private MyWriter, public IWriter {
public:
  void write(std::vector<char> const& data) {
    MyWriter::write(data);
  }
};
class MyOwnClass: private MyWriter, public IWriter {
public:
  void write(std::vector<char> const& data) final = MyWriter::write;
};