Is there a way to pass by value all the sub-classes of an pure abstract class to a function in C++?

Viewed 72

Say I had 2 classes A and B, where A is a pure abstract class with a pure virtual function and B inherits from A and implements the pure virtual function. If I then have a function g() that I want to pass any instance of a subclass of A by value to (so I could mutate it without changing the original instance), how would you do that? I know that the following code does not fit my purposes:

void g(A myObject) {} //doesn't work since A contains a pure virtual function

void g(A* myObject) {} //code compiles, but changes the original instance 

Would I just copy the instance and make a pointer to it and pass into a function like above? Or is there a cleaner way to do this?

2 Answers

I think the best practice here is to leverage clone() method:

#include <iostream>
#include <memory>

class Base
{
public:
    virtual void set_str(std::string) = 0;
    virtual void print() = 0;
    virtual std::unique_ptr<Base> clone() = 0;
};

class Derived: public Base
{
private:
    std::string _str;
public:
    std::unique_ptr<Base> clone() override { 
        return std::make_unique<Derived>(*this); 
    }
    void set_str(std::string str) override {
        this->_str = str;
    }
    void print() override {
        std::cout << this->_str << std::endl;
    }
};

void foo(std::unique_ptr<Base> obj) {
    obj->set_str("inside");
    obj->print();
}

int main() {
    Derived obj;
    obj.set_str("outside");
    foo(obj.clone());
    obj.print();
    return 0;
}

What prevent the copy if indeed the pure virtual function in A. If A could be copy created from its child classes, you would have sliced the original object and only kept the fields present in A.

If you want to prevent modifications, you could:

  • replace the pure virtual function with a function raising an exception. Class A would become creatable while it would still break if you tried to use the function on a non subclassed object.
  • insert a A1 class in the hierachy with the above defined function and use it in g

This both methods create a copy of the original object and pass that (sliced) copy

You could also use a const reference:

void g(const A& myObject);

This will pass a reference to the original object, but the compiler will raise an error if you try to modify it.

Related