从抽象(纯虚)类私有继承有意义吗?

does it make sense to inherit privately from an abstract (pure virtual) class?

本文关键字:继承 有意义 抽象 纯虚      更新时间:2023-10-16

假设这个结构

struct InterfaceForFoo
{
    virtual void GetItDone() = 0;
};

class APoliticallyCorrectImplementationOfFooRelatedThings : private InterfaceForFoo
{
  public:
    void GetItDone() { /*do the thing already*/ };   
};

现在,我想知道以这种方式从接口私有继承是否有任何有用的场景。

嗯,这里每个人都说"不"。我说:"是的,它确实有意义。"

class VirtualBase {
public:
    virtual void vmethod() = 0;
    // If "global" is an instance of Concrete, then you can still access
    // VirtualBase's public members, even though they're private members for Concrete
    static VirtualBase *global;
};
// This can also access all of VirtualBase's public members,
// even if an instance of Concrete is passed in,
void someComplicatedFunction(VirtualBase &obj, ...);
class Concrete : private VirtualBase {
private:
    virtual void vmethod();
public:
    void cmethod() {
        // This assignment can only be done by Concrete or friends of Concrete
        VirtualBase::global = this;
        // This can also only be done by Concrete and friends
        someComplicatedFunction(*this);
    }
};

继承private并不意味着你不能从类外部访问VirtualBase的成员,它只意味着你不能通过对Concrete的引用访问这些成员。但是,Concrete和它的朋友可以将Concrete的实例强制转换为VirtualBase,这样任何人都可以访问公共成员。简单,

Concrete *obj = new Concrete;
obj->vmethod(); // error, vmethod is private
VirtualBase *obj = VirtualBase::global;
obj->vmethod(); // OK, even if "obj" is really an instance of Concrete

问题是为什么基类只有纯虚方法很重要?

这两件事几乎没有关系。私有意味着它是类的实现细节,而不是公共接口的一部分,但您可能希望将接口实现为实现细节。假设您编写了一个类,并且您决定通过需要您实现接口的库来实现该功能。这是一个实现细节,没有必要仅仅因为接口只有纯虚函数而将继承设为public

在面向对象方面,对于抽象的class,没有private继承的用例。

然而,如果你想强制你的子class必须派生某些方法,那么你可以使用这个。例如:

struct implement_size
{
  virtual size_t size () = 0;
};
class MyVector : private implement_size
{
public:
  size_t size () { ... } // mandatory to implement size()
}
class MyString : private implement_size
{
public:
  size_t size () { ... } // mandatory to implement size()
};
所以,它只是有助于维护个人编码纪律。这个例子传递的信息是,继承不仅仅是为了面向对象的目的。您甚至可以使用继承来停止继承链(类似于Java final)。

嗯?不,这完全没有意义,因为您提供接口的原因是希望其他人通过该接口使用您的类。如果他们不知道你在执行它,那该怎么做呢?

#include <vector>
class Fooable{
public:
  virtual void foo() = 0;
};
class DoesFoo
  : private Fooable
{
  void foo();
};
int main(){
  std::vector<Fooable*> vf;
  vf.push_back(new DoesFoo()); // nope, doesn't work
  vf[0]->foo();
}

上面的示例不起作用,因为外部世界不知道DoesFooFooable,因此您不能new它的实例并将其分配给Fooable*

不完全是。如果你需要一个函数,你就实现它。强制一个不能被其他类使用的函数是没有意义的。

为什么要从接口中私有继承,我不知道;这有点违背了接口的目的。

如果它不是一个接口,而是一个类,它是有意义的:

class A {
    virtual void foo() = 0;
    void bar() {
        foo();
    }
};
class B : private A {
    virtual void foo() {
    }
};