为什么 C++ 不让基类实现派生类的继承接口?

2021-12-09 00:00:00 class inheritance interface c++

这就是我要说的

// some guy wrote this, used as a Policy with templates
struct MyWriter {
  void write(std::vector<char> const& data) {
    // ...
  }
};

在现有的一些代码中,人们没有使用模板,而是使用接口+类型擦除

In some existing code, the people did not use templates, but interfaces+type-erasure

class IWriter {
public:
  virtual ~IWriter() {}

public:
  virtual void write(std::vector<char> const& data) = 0;
};

其他人想要同时使用方法和写入

Someone else wanted to be usable with both approaches and writes

class MyOwnClass: private MyWriter, public IWriter {
  // other stuff
};

MyOwnClass 是根据 MyWriter 实现的.为什么MyOwnClass的继承成员函数没有自动实现IWriter的接口?相反,用户必须编写只调用基类版本的转发函数,如

MyOwnClass is implemented-in-terms-of MyWriter. Why doesn't MyOwnClass' inherited member functions implement the interface of IWriter automatically? Instead the user has to write forwarding functions that do nothing but call the base class versions, as in

class MyOwnClass: private MyWriter, public IWriter {
public:
  void write(std::vector<char> const& data) {
    MyWriter::write(data);
  }
};

我知道在 Java 中,当您有一个实现接口并从恰好具有合适方法的类派生的类时,该基类会自动实现派生类的接口.

I know that in Java when you have a class that implements an interface and derives from a class that happens to have suitable methods, that base class automatically implements the interface for the derived class.

为什么 C++ 不这样做?拥有这似乎是一件很自然的事情.

Why doesn't C++ do that? It seems like a natural thing to have.

推荐答案

这是多重继承,有两个继承的函数,签名相同,都有实现.这就是 C++ 与 Java 不同的地方.

This is multiple inheritance, and there are two inherited functions with the same signature, both of which have implementation. That's where C++ is different from Java.

在静态类型为 MyBigClass 的表达式上调用 write 因此对于需要哪个继承函数是不明确的.

Calling write on an expression whose static type is MyBigClass would therefore be ambiguous as to which of the inherited functions was desired.

如果 write 仅通过基类指针调用,则不需要在派生类中定义 write,这与问题中的声明相反. 既然问题已更改为包含纯说明符,那么在派生类中实现该函数对于使类具体化和可实例化是必要的.

If write is only called through base class pointers, then defining write in the derived class is NOT necessary, contrary to the claim in the question. Now that the question changed to include a pure specifier, implementing that function in the derived class is necessary to make the class concrete and instantiable.

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

MyWriter::write cannot be used for the virtual call mechanism of MyBigClass, because the virtual call mechanism requires a function that accepts an implicit IWriter* const this, and MyWriter::write accepts an implicit MyWriter* const this. A new function is required, which must take into account the address difference between the IWriter subobject and the MyWriter subobject.

编译器自动创建这个新函数在理论上是可能的,但它很脆弱,因为基类的变化可能会突然导致选择一个新函数进行转发.它在 Java 中不那么脆弱,只有单继承是可能的(对于要转发到哪个函数只有一种选择),但是在支持完全多重继承的 C++ 中,选择是不明确的,我们甚至还没有开始钻石继承或虚拟继承.

It would be theoretically possible for the compiler to create this new function automatically, but it would be fragile, since a change in a base class could suddenly cause a new function to be chosen for forwarding. It's less fragile in Java, where only single inheritance is possible (there's only one choice for what function to forward to), but in C++, which supports full multiple inheritance, the choice is ambiguous, and we haven't even started on diamond inheritance or virtual inheritance yet.

其实这个问题(子对象地址之间的差异)是通过虚拟继承解决的.但它需要额外的开销,这在大多数情况下是不必要的,而 C++ 的指导原则是不用为不使用的东西付费".

Actually, this problem (difference between subobject addresses) is solved for virtual inheritance. But it requires additional overhead that's not necessary most of the time, and a C++ guiding principle is "you don't pay for what you don't use".

相关文章