【问题标题】:Using base class rather than base pointer to work on derived class使用基类而不是基指针来处理派生类
【发布时间】:2016-05-01 11:49:23
【问题描述】:

我有一个像这样的基本抽象类;

class X {
public:
    virtual ~X(){}
    virtual doSomething() = 0;
};

然后我用 Y、Z 等几个类来实现这个,每个类都有自己的构造函数、析构函数和 doSomething 实现。在我的主要功能中我做;

int main(){
    std::vector<X *> v;
    X *x1 = new Y();
    X *x2 = new Z();
    v.push_back(x1);
    v.push_back(x2);
    for(auto p : v){
        p->doSomething()
    }
}

这会按预期调用相应的 doSomething 实现。但我的问题是我正在使用指向抽象类的指针来通过其基类操作派生类的层次结构。这迫使我使用 new 在堆上创建实例,之后我必须手动删除它们。有没有办法做这样的事情;

int main(){
    std::vector<X> v;
    Y x1();
    Z x2();
    v.push_back(x1);
    v.push_back(x2);
    for(auto p : v){
        p.doSomething()
    }
}

这样当我退出 main 时会自动调用析构函数。我知道我不能创建抽象类的成员,但是使用指针来实现这一切似乎很奇怪。当然,必须有一种方法可以在没有指针和新删除的情况下做到这一点。如果有人向我展示了最佳实践,那就太好了。

【问题讨论】:

    标签: c++ inheritance


    【解决方案1】:

    您想使用合适的智能指针:

    std::vector<std::unique_ptr<X>> v;
    
    v.push_back(std::make_unique<Y>());
    v.push_back(std::make_unique<Z>());
    
    // all done
    

    (当然还有动态分配,因为如果没有运行时间接,您无法管理无限数量的无约束类型,但您永远不必考虑手动进行任何动态管理。类型系统可以为您完成所有工作。)

    【讨论】:

    • 我很好奇你是否认为 push_back(make_unique&lt;Y&gt;())emplace_back(new Y) 更好。
    • 嗯,我想我应该在我的第一条评论中包含这个,但是:为什么?
    • @JohnZwinck:你应该有! (例如,通过将“if”更改为“why”。)答案是因为 a)您永远不想在代码中说 new,b)您希望您的代码在子表达式方面是正确的,以及 c)因为 push -back(添加值)在语义上更简单,并且比更具侵入性的 emplacement(用于通过显式构造函数直接初始化)更好地分割职责。
    • @meguli:朋友之间的交易怎么样:你在接下来的 24 小时里都在搜索互联网,尤其是 Stack Overflow,以获取 unique_ptr 的解释和使用示例。然后,如果在那之后您仍然不确定,请告诉我,我会写下更多细节。怎么样?
    • @meguli:C++11 之前的版本要困难得多,因为缺少右值引用,类型系统要弱得多,所以你无法表达很多真正有用的东西类型系统中的“职责转移”语义。那是黑暗的日子:-S
    【解决方案2】:

    尽管 Kerrek SB 发布了很好的答案,但 OP 要求提供解决方案(让我说)new-free,值得为此再添加一个答案。


    您可以使用std::reference_wrapper
    它遵循一个最小的工作示例:

    #include<vector>
    #include<functional>
    #include<iostream>
    
    class X {
    public:
        virtual ~X(){}
        virtual void doSomething() = 0;
    };
    
    class Y: public X {
        void doSomething() override {
            std::cout << "Y" << std::endl;
        }
    };
    
    class Z: public X {
        void doSomething() override {
            std::cout << "Z" << std::endl;
        }
    };
    
    int main(){
        std::vector<std::reference_wrapper<X>> v;
        Y x1{};
        Z x2{};
        v.emplace_back(x1);
        v.emplace_back(x2)
        for(X &p : v){
            p.doSomething();
        }
    }
    

    请注意,在这种情况下,您必须保证存储对象的生命周期超过向量之一。
    如果您打算使用 std::unique_ptrs,则不会遇到此问题,正如 Kerrek SB 在其他答案中所建议的那样。

    【讨论】:

    • Kerrek SB 建议 std::unique_ptr,而不是 std::shared_ptr
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-11
    • 2013-11-04
    相关资源
    最近更新 更多