Search code examples
c++classinheritanceabstract-class

How to have base abstract class object as class member but accept derived class memebers in constructor?


Setup

I've encountered the following situation in my C++ code (this is an example to illustrate the problem, and has not much to do with the actual code). I have a virtual class Family and two classes that I derive from it:

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; }
};

Then I have another class Car. This class should have a private member that can be either an object from the Mother or Father class. I tried to implement this as

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

If one tries to run the above via the main function

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

I get the error that member in the constructor of Car cannot be declared since Family is abstract. I understand the problem and why this happens, but I don't know what the right tool in C++ is to solve the problem. Unfortunately I also don't know how to google this properly (I didn't really find any suitable suggestions).


What I tried so far

The only idea that I had was to remove the abstract class altogether and template the Car class. I'd like to avoid this, since in the original problem the two derived classes logically belong to a "superclass", so I don't want to introduce this split if it is not absolutely necessary.


Solution

  • You need to use references or pointers for polymorphism. One possible solution would be:

    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
    }
    

    Don't forget to delete the pointers once you are done with them.
    If you can use c++11 (c++14 for std::make_unique) or higher, using smart-pointers is even better:

    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
    }