存储抽象成员,保持接口简单

store abstract member, keep interface simple

本文关键字:接口 简单 抽象 成员 存储      更新时间:2023-10-16

我知道它是可能有一个抽象类的实例作为另一个类的基成员,即

#include <iostream>
class Base {
  public:
    Base() {};
    virtual ~Base() {};
    virtual int yield() = 0;
};
class C1: public Base {
  public:
    C1(): Base() {};
    virtual ~C1() {};
    virtual int yield() {return 1;};
};
class D {
  public:
    D(Base & b): b_(b) {};
    virtual ~D() {};
  private:
    Base b_;
}
int main() {
  C1 c;
  D d(c);
}

将编译失败,并出现错误

test.cpp:22:10: error: cannot declare field ‘D::b_’ to be of abstract type ‘Base’

显而易见的解决方法是使用(共享)指针。然而,这使得main的读取更加复杂,

int main() {
  auto c = std::make_shared<C1>();
  D d(c);
}

我真的很想避免。

是否有一种方法可以保持main文件像上面的示例一样简单,并且仍然实现所需的功能?

你不能。当您创建D时,它为B分配(在堆或堆栈中)内存。C1类需要基类B的大小加上C1本身的额外变量/等的大小,即使没有新的。

virtual int yield() = 0;导致的错误。如果您使用virtual int yield(),它将工作。当您使用virtual int yield() = 0;时,它说该函数是pure virtual函数,因此您必须override它。所以你应该给它inheritance class,在class C1中使用the instance of inheritance class。在一个世界里,virtual int yield() = 0;只是提醒你它只是一个接口,你必须覆盖它。我希望这对你有帮助。

因为Base是一个抽象类(至少有一个纯虚函数),所以不能直接实例化它。当您将D的类成员声明为"Base b_"时,您实际上是在尝试创建一个实例。你可以在这里使用指针(或者某种安全/智能指针)。

#include <iostream>
class Base {
  public:
    Base() {};
    virtual ~Base() {};
    virtual int yield() = 0;
};
class C1: public Base {
  public:
    C1(): Base() {};
    virtual ~C1() {};
    virtual int yield() {return 1;};
};
class D {
  public:
    D(Base * b): b_(b) {};
    virtual ~D() {};
  private:
    Base *b_;  // Use a pointer or safe ptr or something of that sort.
}
int main() {
  C1 c;
  D d(&c);
}

No。抽象类的一个属性是它不能被实例化。这意味着抽象类的实例不能是另一个类的成员。

即使Base不是抽象的,类D的构造函数也会对传递的对象进行切片。如果传递一个C1的实例,复制(在D的构造函数的初始化列表中)不会神奇地导致D的实例包含一个C类型的对象。相反,它只会创建该对象的Base部分的副本。

简而言之,你的设计是坏的,即使在语法上可以简化main()中的代码,也不能工作。