如何将基类的未知子类放在一个数据结构中并在 C++ 中调用重写的基类函数

Posted

技术标签:

【中文标题】如何将基类的未知子类放在一个数据结构中并在 C++ 中调用重写的基类函数【英文标题】:How to put unknown child classes of a base class in one data structure and call an overridden base class function in C++ 【发布时间】:2020-12-31 01:04:12 【问题描述】:

我有一个“链”类,意思是管理具有公共基类的一系列对象的类。 这个链类应该为我添加的任何子类(baseClass)执行成员函数processSample(a, b)

我希望以后能够编写更多子类(使用processSample(a, b) 函数),并将它们添加到链中,而无需编辑链类。 我可以在add 函数中使用模板,但这并不能解决不同数据类型(不同大小)没有数据结构的问题,对吧?

Chain 类中调用的子类的函数都应该被基类中的虚函数覆盖。

class baseClass

public:

    virtual float processSample(int a, float b)
    

    
;


class Chain

    const int maxChilds = 20;
    ?sometype? allChilds[maxChilds];

public:
    float processSample(int c, float d)
    
        for (int i = 0; i < maxChilds; i++)
        
            input = allChilds[i].processSample(a, b);
        

        return input;
    

    void addChild(?sometype? newChild)
    
       allChilds.push_back(newChild)
    

【问题讨论】:

?sometype? -> baseClass * 最有可能,但您可能需要baseClasss 的簿记计数器,由allChilds 指向。如果不添加 maxChilds 实例,迭代到 maxChilds 将是致命的。 std::vector&lt;baseClass*&gt;std::vector&lt;std::reference_wrapper&lt;baseClass&gt;&gt; @ChrisD 拥有此权利。 C++ 中的原始数组没有 push_back 方法。或者任何方法。数组真的很简单也很笨。 这能回答你的问题吗? Store derived class objects in base class variables 【参考方案1】:

您可能希望使用指针或引用,以避免初始化或复制操作作为创建类的一部分。

例如

class Chain

    const int maxChilds = 20;
    baseClass allChilds[maxChilds];

将创建并初始化一个包含 20 个基类实例的数组。而这个:

class Chain

    const int maxChilds = 20;
    baseClass* allChilds[maxChilds];

将创建一个指向 baseClass 的指针数组,它也可以指向任何子类的实例。请考虑哪个类将负责为这些实例分配和取消分配内存(这可以在此类中,也可以在此类的调用者/用户中 - 哪个是理想的将取决于您的设计的其余部分) .你也可以考虑使用智能指针,让它为你管理内存:https://en.cppreference.com/book/intro/smart_pointers

同样:

void addChild(baseClass newChild)

将使用传值传递newChild的副本(使用baseClass的复制构造函数),任何子类的实例都将失败或转换为baseClass的实例。而如果你改为选择:

void addChild(baseClass& newChild)

它将改为使用传递引用,并且该函数将接收对原始对象的引用。

【讨论】:

请注意,要使addChild 真正起作用,您必须绝对确定添加的节点的生命周期匹配或超过Chain 的生命周期。通常你需要a clone method 来创建一个寿命更长的实例,而Chain 拥有它的所有权。 是的 - 代码中还有很多其他错误需要修复:)。我想我会坚持只解决所问的问题,特别是因为复制构造函数/按值传递行为对于来自 Java 之类的东西都是按引用传递的人来说是一个重要的区别。跨度> 【参考方案2】:

virtual 的好处是“调用基类的函数”,而派生类的函数会被执行。

所以?sometype? allChilds[maxChilds];baseClass allChilds[maxChilds];。链应该是对象的持有者,所以addChild(...) 不应该接受子类的实例。它应该创建实例并使用(如有必要)std::move 将其添加到数组中。

备注:使用会更方便

std::vector<baseClass>allChilds;
allChilds.reserve(maxChilds); //reserves the memory but you can still use push back

【讨论】:

以上是关于如何将基类的未知子类放在一个数据结构中并在 C++ 中调用重写的基类函数的主要内容,如果未能解决你的问题,请参考以下文章

将基类指针强制转换为子类指针后的疑惑

C#:将基类转换为子类

请教C++高手: 关于类的继承,当子类以public方式继承基类之后,根据继承的规则,基类的所有数据成员和成

C ++将派生类的属性设置为从同一基类派生的未知类对象?

将基类的对象传递给派生类的引用函数

C++中如何在子类的构造函数中调用基类的构造函数来初始化基类成员变量