【问题标题】:How to have base abstract class object as class member but accept derived class memebers in constructor?如何将基抽象类对象作为类成员但在构造函数中接受派生类成员?
【发布时间】:2020-08-21 11:17:00
【问题描述】:

设置

我在我的C++代码中遇到过以下情况(这是一个例子来说明问题,与实际代码没有太大关系)。我有一个虚拟类 Family 和两个从中派生的类:

class Family {
    public:
        virtual double operator()(double const & x) const = 0;
        virtual ~Family();
};


class Mother : public Family {
    public:
        double operator()(double const & x) const override { return x*x; }
};

class Father : public Family {
    public:
        double operator()(double const & x) const override { return x-2; }
};

然后我有另一堂课Car。这个类应该有一个私有成员,它可以是来自MotherFather 类的对象。我试图将其实现为

class Car {
    public:
        Car(Family member) : right_seat_(member)  {}
    private:
        Family right_seat_;
};

如果尝试通过 main 函数运行上述代码

int main(){
    Mother lucy = Mother();
    Car Van = Car(lucy);
}

我得到一个错误,Car 的构造函数中的member 不能被声明,因为Family 是抽象的。我了解这个问题以及为什么会发生这种情况,但我不知道 C++ 中解决问题的正确工具是什么。不幸的是,我也不知道如何正确地用谷歌搜索(我真的没有找到任何合适的建议)。


到目前为止我尝试了什么

我唯一的想法是完全删除抽象类并将Car 类模板化。我想避免这种情况,因为在原始问题中,两个派生类在逻辑上属于“超类”,所以如果不是绝对必要,我不想引入这种拆分。

【问题讨论】:

    标签: c++ class inheritance abstract-class


    【解决方案1】:

    您需要使用引用或指针来实现多态性。一种可能的解决方案是:

    class Car {
        public:
            Car(Family* member) : right_seat_(member)  {}
        private:
            Family* right_seat_;
    };
    
    int main(){
        Mother* lucy = new Mother();
        Car Van = Car(lucy);
        ...//do stuff with car
    }
    

    完成后不要忘记delete指针。
    如果你可以使用 c++11 (c++14 for std::make_unique) 或更高版本,使用智能指针会更好:

    class Car {
        public:
            Car(std::unique_ptr<Family>&& member) : right_seat_(std::move(member))  {}
        private:
            std::unique_ptr<Family> right_seat_;
    };
    
    int main(){
        std::unique_ptr<Family> lucy = std::make_unique<Mother>();
        Car Van = Car(std:move(lucy));
        ...//do stuff with car
    }
    

    【讨论】:

    • 需要指针或引用是的,但需要手动动态内存否。如果Car 需要引用,Mother lucy; Car Van = Car(lucy); 将起作用。或使用指针:Mother lucy; Car Van = Car(&amp;lucy);。你正在泄漏内存
    • @idclev463035818 是的,这就是为什么我明确指出需要删除指针的原因(但不知道该删除的位置,因为这取决于 OP 希望如何管理对象生命周期) .
    • 我的观点是:没有必要管理生命周期。使用自动存储,您不能忘记删除。您引入了 OP 代码中不存在的问题
    • 为什么要这样创建 Van 对象 Car Van = Car(&lucy)?我认为这是用于创建对象的更多 java 风格或格式。您可以简单地使用 Car Van{&lucy} 创建 Van 对象。不是更好吗?
    • @Sito 我的错,忘了std::move。固定。
    【解决方案2】:

    抽象类不能成为成员,因为它们不能被实例化。

    动态多态性需要间接性。你可以拥有一个指向抽象基的指针。

    这个类应该有一个私有成员,它可以是来自 Mother 或 Father 类的对象。

    C++ 中的变量不能有时具有一种类型而有时具有另一种类型。每个变量都有确切的类型,除了在模板中,模板的不同实例可以有不同的类型。

    同样,这就是你需要间接的地方:你可以有一个指向基类的指针,而哪个派生类包含该基类并不重要。

    如果您希望Car 拥有(即控制并负责其生命周期)间接引用的家庭,因为它会拥有一个成员,那么您需要使用动态分配。也就是说,从设计的角度来看,这种所有权关系似乎是可疑的。

    【讨论】:

      猜你喜欢
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 2023-03-31
      • 2015-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多