C++中的对象合成 我试图在C++中实现一种特定的对象合成。其思想是创建一组所有数据结构,这些数据结构可以通过组合只知道基本数据结构操作的抽象类来创建。例如,堆栈将通过组合一个pusher和一个popper来创建,队列将通过组合一个queuer和一个popper来创建,等等

C++中的对象合成 我试图在C++中实现一种特定的对象合成。其思想是创建一组所有数据结构,这些数据结构可以通过组合只知道基本数据结构操作的抽象类来创建。例如,堆栈将通过组合一个pusher和一个popper来创建,队列将通过组合一个queuer和一个popper来创建,等等,c++,data-structures,abstract-class,object-composition,C++,Data Structures,Abstract Class,Object Composition,问题是,尽管Pusher、Popper和Queuer只是作为抽象类使用,因此永远不会被实例化,但它们必须知道数据结构如何在内部存储数据 我们的目标是拥有不可知的抽象类,这些抽象类仅用于以以下方式将方法定义传递给具体的数据结构类: 阶级推动者{ 公众: 无效Pushint值{ //模拟推送值的内部逻辑。 元素。推回值; } } 类波普尔{ 公众: int-Pop{ //模拟弹出值的内部逻辑。 int popped_value=elements.back; 元素。返回; 返回弹出的_值; } } 类

问题是,尽管Pusher、Popper和Queuer只是作为抽象类使用,因此永远不会被实例化,但它们必须知道数据结构如何在内部存储数据

我们的目标是拥有不可知的抽象类,这些抽象类仅用于以以下方式将方法定义传递给具体的数据结构类:

阶级推动者{ 公众: 无效Pushint值{ //模拟推送值的内部逻辑。 元素。推回值; } } 类波普尔{ 公众: int-Pop{ //模拟弹出值的内部逻辑。 int popped_value=elements.back; 元素。返回; 返回弹出的_值; } } 类堆栈:公共Pusher,公共Popper{ 私人: 矢量元素; } 您可以看到,尽管Pusher和Popper不知道元素,但Stack知道,这才是最重要的。但是,此代码无效,无法编译。我怎样才能写出同样有效的东西呢

尽管Pusher和Popper不知道元素,Stack知道,这才是最重要的

不是所有的都和C++相关的重要,正如你可以清楚地看到的,并且有充分的理由。你的建议有很多缺点,因此是不允许的。但是,有几种方法可以绕过此限制

一种方法是使用虚拟继承,并定义一个称为的抽象基类,例如,Store,它通过在堆栈中实现的虚拟函数提供对Pusher和Popper操作的存储的访问

但是,通常在C++中避免。更惯用的方法是使用

将Pusher和Popper更改为以Stack类为模板参数的类模板:

template <typename T>
class Pusher {
  public:
    void Push(int value) {
      // Simulates internal logic of pushing a value.
      T::elements(*this).push_back(value);
    }
};

template <typename T>
class Popper {
  public:
    int Pop() {
      // Simulates internal logic of popping a value.
      int popped_value = T::elements(*this).back();
      T::elements(*this).pop_back();
      return popped_value;
    }
};

class Stack: public Pusher<Stack>, public Popper<Stack> {
  public:
    template <typename T>
    static std::vector<int>& elements(T& s) {
        return static_cast<Stack&>(s).elements_;
    }
  private:
    std::vector<int> elements_;
};
不用说,这仍然是非常复杂的,因为您的数据依赖性是颠倒的。仔细考虑你的特质需要哪些依赖性,以及它们是如何有用的


另一个实现,也是接近标准库的实现,是将Pusher和Popper实现为:也就是说,它们从堆栈继承,而不是相反。这可能很有用,但只有在更改名称时才有用:显然,拥有既不执行推送也不执行弹出的类堆栈是没有意义的。再次,看看std::stack adapter类的接口以获得灵感。

您是否尝试了一个公共容器基类,并使用了虚拟继承?使用CRTP如何?使用模板类存储容器对象的引用如何?>您所建议的方法有许多缺点,因此是不允许的。您能解释一下缺点是什么吗?@Logorrhea解析器必须接受无效代码,因为如果正确使用该类,代码可能会变得有效。但是,例如,如果用户随后创建了Pusher类型的对象,该怎么办?那将是不恰当的。为了提供更好的诊断,编译器禁止推送器的定义,而不仅仅是它的使用。如果C++中的C语言的抽象类类似于语言,那么这将是很好的,这可以防止您对它们进行实例化。谢谢您的回答。干杯。@RobertAndrzejuk不确定你想用这句话说什么…