Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default copyable derived classes

Tags:

c++

Suppose I have a silly class hierarchy.

class Base {
public:
    Base() = default;
    virtual ~Base() = default;
    virtual void print() = 0;
};

class Derived : public Base {
public:
    Derived() {
        stuff.resize(1000);
    }
    void print() override {
        cout << "Whatever\n";
    }
private:
    std::vector<int> stuff;
};

And I want to use it like this:

void printIt(Base* b) {
    b->print();
}

int main() {

    Derived d1;
    Derived d2 = d1;

    printIt(&d1);
    printIt(&d2);
}

This compiles and works fine, but Clang warns me:

warning: definition of implicit copy constructor for 'Base' is deprecated because it has a user-declared destructor

That seems fine and correct - if people copy Base bad things will happen so I'll delete the copy constructor.

class Base {
public:
    Base() = default;
    virtual ~Base() = default;
    virtual void print() = 0;

    Base(const Base&) = delete;
    Base& operator=(const Base&) = delete;
};

However then I get this error:

main.cpp:38:17: error: call to implicitly-deleted copy constructor of 'Derived'
        Derived d2 = d1;
                ^    ~~
main.cpp:18:21: note: copy constructor of 'Derived' is implicitly deleted because base class 'Base' has a deleted copy
      constructor
    class Derived : public Base {
                    ^
main.cpp:14:9: note: 'Base' has been explicitly marked deleted here
        Base(const Base&) = delete;
        ^

Ok... fair enough. What if I try to add it back in explicitly?

class Derived : public Base {
public:
    Derived() {
        stuff.resize(1000);
    }
    void print() override {
        cout << "Whatever\n";
    }

    Derived(const Derived&) = default;

private:
    std::vector<int> stuff;
};

Then:

main.cpp:40:17: error: call to implicitly-deleted copy constructor of 'Derived'
        Derived d2 = d1;
                ^    ~~
main.cpp:27:9: note: explicitly defaulted function was implicitly deleted here
        Derived(const Derived&) = default;
        ^
main.cpp:18:21: note: copy constructor of 'Derived' is implicitly deleted because base class 'Base' has a deleted copy
      constructor
    class Derived : public Base {
                    ^
main.cpp:14:9: note: 'Base' has been explicitly marked deleted here
        Base(const Base&) = delete;
        ^

No joy, which also kind of makes sense. What is the solution here? Should I just ignore the original warning? Maybe I should add Base(Base&) etc as protected?

like image 204
Timmmm Avatar asked Nov 29 '25 07:11

Timmmm


1 Answers

So it does compile without warnings if I make the copy/assignment protected. This seems like a reasonable solution:

class Base {
public:
    Base() = default;
    virtual ~Base() = default;
    virtual void print() = 0;

protected:        
    Base(const Base&) = default;
    Base& operator=(const Base&) = default;
};

class Derived : public Base {
public:
    Derived() {
        stuff.resize(1000);
    }
    void print() override {
        cout << "Whatever\n";
    }

private:
    std::vector<int> stuff;
};

void printIt(Base* b) {
    b->print();
}

int main() {

    Derived d1;
    Derived d2 = d1;

    printIt(&d1);
    printIt(&d2);
}
like image 64
Timmmm Avatar answered Dec 01 '25 22:12

Timmmm