繁体   English   中英

如何将子类作为期望基类的函数的参数传递,然后将该对象传递到指向这些抽象类对象的指针向量中?

[英]how to pass subclass as parameter for function expecting base class then pass that object into vector of pointers to those abstract class objects?

TL; 博士

我试图将一个子类传递给一个函数,该函数需要子类的基类,然后将该基类的唯一指针存储在第三个完全独立的类中的向量中。

(C++ 11 及更高版本)

结束 TL;DR

我总共有 3 个课程,然后是我的int main()

基(抽象)类有一个构造函数和一个虚函数。 实现了基类构造函数,没有实现虚函数。

第二个类是基类的子类。 它实现自己的构造函数并调用基本构造函数。 子类的第二部分是虚基类函数的具体实现。

然后我有第三个类,它有自己的构造函数。 这第三个类有一个函数,其函数头包含对基类的引用。 这个相同的函数然后尝试将此引用传递给抽象类,然后将.push_back()引用传递到此抽象类的std::unique_ptr向量中。 (因为我不能直接拥有抽象类实例的向量。)

我的问题是我目前无法获得此代码的一个版本进行编译。

我一直在网上参考一些资源来尝试解决我的问题。

pass unique_ptr as an object
https://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function

adding elements of a vector of a base class
https://stackoverflow.com/questions/31410858/adding-elements-to-stdvector-of-an-abstract-class

can't access derived class method from pointer of base class - not entirely relavent, but good knowledge
https://stackoverflow.com/questions/23489554/cant-access-derived-class-method-from-pointer-of-type-base-class

我在一个无法编译的示例 C++ 可执行文件中创建了这个问题的缩短版本。

这是文件:


/*
This script demonstrates my dilemma of trying to pass a subclass object
as a parameter to a function that expects the base class, and then 
take that passed in object in the function and add it to a vector of that object 
in a completely different class.
*/

#include <iostream>
#include <memory>
#include <vector>

class Baseclass
{
    public:
        Baseclass(int i)
        {
            lala = i;
        }

    // subclass MUST implement this method.
    virtual int addme(int d) = 0;

    protected:
        int lala;
};

class Subclass : Baseclass
{
    public:
        Subclass(int d, int l) : Baseclass(d)
        {
            blahblah = l;
        }

        int addme(int d)
        {
            return blahblah + lala + d;
        }

    protected:
        int blahblah;
};

class Mainclass
{
    public:
        Mainclass(uint blah)
        {
            anotherone = blah;
        }

        // This is the function I cannot seem to get to work.
        // How can I make the function parameter an abstract class?
        // The object being passed in is NOT abstract...
        bool addController(Baseclass & basecont)
        {
            // This line here does NOT compile!!
            // controllers.push_back(std::make_unique<What goes here?>(basecont));
            return true;
        }

    protected:
        uint anotherone;
        std::vector<std::unique_ptr<Baseclass>> controllers;
};

int main(int argc , char ** argv)
{
    // create subclassed controllers
    Subclass cont1 = Subclass(12, 23);
    Subclass cont2 = Subclass(233, 2);
    // create main object
    Mainclass mainbro = Mainclass(23);
    // Add the subclased controllers to the main class
    // THESE 2 lines do not compile!!
    // mainbro.addController(cont1);
    // mainbro.addController(cont2);
    //
    return 0;
}

我认为我做错了什么,但我不认为我概述的过程本身是不可能的。 我只是认为我在解决这个问题是错误的。

我在脚本中强调了我不确定我应该做什么以及代码在哪里中断。

我可能需要对问题采取替代方法,我只是不知道我有哪些替代方法。

我看到了修复代码的不同方法,具有不同的含义。

  • 存储指针( main拥有对象的所有权)

     class Mainclass { public: void addController(Baseclass& basecont) { controllers.push_back(&basecont); } protected: std::vector<Baseclass*> controllers; };
  • 所有权转让

    class Mainclass { public: void addController(std::unique_ptr<Baseclass> basecont) { controllers.push_back(std::move(basecont)); } protected: std::vector<std::unique_ptr<Baseclass>> controllers; };

    main

     int main() { auto cont1 = std::make_unique<Subclass>(12, 23); auto cont2 = std::make_unique<Subclass>(233, 2); Mainclass mainbro(23); mainbro.addController(std::move(cont1)); mainbro.addController(std::move(cont2)); }
  • 存储副本

    class Mainclass { public: void addController(Baseclass& basecont) { controllers.push_back(basecont.clone()); } protected: std::vector<std::unique_ptr<Baseclass>> controllers; };

    class Baseclass { // ... public: virtual int addme(int d) = 0; virtual std::unique_ptr<Baseclass> clone() = 0; }; class Subclass : Baseclass { // ... public: std::unique_ptr<Baseclass> clone() override { return std::make_unique<Subclass>(*this); } };

每当您将基指针或引用与虚拟方法一起使用时,请始终添加虚拟析构函数:

    virtual ~Baseclass() = default;

当基指针被删除时,这可以防止未定义的行为。

下一步,使用公共继承允许编译器从unique_ptr<Subclass>隐式向上转换到unique_ptr<Baseclass>

class Subclass : public Baseclass

您的最后一个问题是所有权问题。 通过使用unique_ptr向量,您是在说您的类拥有所有这些对象。 但是通过在main的堆栈上声明它们,您是在说main拥有它们。 相反,在主程序中使用make_unique ,并使用std::move转移所有权:

        bool addController(std::unique_ptr<Baseclass> basecont)
        {
            controllers.push_back(std::move(basecont));
            return true;
        }

...

    auto cont1 = std::make_unique<Subclass>(12, 23);
    auto cont2 = std::make_unique<Subclass>(233, 2);
    // create main object
    Mainclass mainbro = Mainclass(23);
    mainbro.addController(std::move(cont1));
    mainbro.addController(std::move(cont2));

全部一起:

#include <iostream>
#include <memory>
#include <vector>

class Baseclass
{
    public:
        Baseclass(int i)
        {
            lala = i;
        }

    virtual ~Baseclass() = default;

    // subclass MUST implement this method.
    virtual int addme(int d) = 0;

    protected:
        int lala;
};

class Subclass : public Baseclass
{
    public:
        Subclass(int d, int l) : Baseclass(d)
        {
            blahblah = l;
        }

        int addme(int d)
        {
            return blahblah + lala + d;
        }

    protected:
        int blahblah;
};

class Mainclass
{
    public:
        Mainclass(uint blah)
        {
            anotherone = blah;
        }

        bool addController(std::unique_ptr<Baseclass> basecont)
        {
            controllers.push_back(std::move(basecont));
            return true;
        }

    protected:
        uint anotherone;
        std::vector<std::unique_ptr<Baseclass>> controllers;
};

int main(int argc , char ** argv)
{
    // create subclassed controllers
    auto cont1 = std::make_unique<Subclass>(12, 23);
    auto cont2 = std::make_unique<Subclass>(233, 2);
    // create main object
    Mainclass mainbro = Mainclass(23);
    mainbro.addController(std::move(cont1));
    mainbro.addController(std::move(cont2));
    return 0;
}

演示: https : //godbolt.org/z/EyQD6S

#include <iostream>
#include <memory>
#include <vector>

class Baseclass
{
    public:
        Baseclass(int i)
        {
            lala = i;
        }

    // subclass MUST implement this method.
    virtual int addme(int d) = 0;

    protected:
        int lala;
};

class Subclass : public Baseclass
{
    public:
        Subclass(int d, int l) : Baseclass(d)
        {
            blahblah = l;
        }

        int addme(int d)
        {
            return blahblah + lala + d;
        }

    protected:
        int blahblah;
};

class Mainclass
{
    public:
        Mainclass(uint blah)
        {
            anotherone = blah;
        }

        // you need to make the function a template, otherwise 
        // you'll slice the top off the SubClass, and incorrectly
        // make a copy of the base class (which you can't do, 
        // because BaseClass is pure virtual)
        template<typename T>
        bool addController(T& basecont)
        {
            // dont push_back new unique_ptrs, emplace_back instead!
            controllers.emplace_back(new T(basecont));
            return true;
        }

    protected:
        uint anotherone;
        std::vector<std::unique_ptr<Baseclass>> controllers;
};

int main(int argc , char ** argv)
{
    // create subclassed controllers
    Subclass cont1 = Subclass(12, 23);
    Subclass cont2 = Subclass(233, 2);
    // create main object
    Mainclass mainbro = Mainclass(23);

    // It's worth pointing out that these methods will take new copies of 
    // cont1 and cont2 (we don't want the mainbro instance to delete the 
    // memory for cont1 and cont2, since they are stack allocated)
    mainbro.addController(cont1);
    mainbro.addController(cont2);
    //
    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM