1

Assume I want to suppress copying/moving in a base class, but allow it for a derived class. I can accomplish the functionality like this:

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

    virtual bool magic() const;

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

class Derived : public Base {
public:
    Derived() = default;
    Derived(int x, double y) : x_(x), y_(y) {};

    bool magic() const;

private:
    int x_;
    double y_;
}

The "problem" is that this doesn't follow C.67 in the ISO C++ Core Guidelines: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-copy-virtual

C.67 states

C.67: A polymorphic class should suppress public copy/move

Reason A polymorphic class is a class that defines or inherits at least one virtual function. It is likely that it will be used as a base class for other derived classes with polymorphic behavior. If it is accidentally passed by value, with the implicitly generated copy constructor and assignment, we risk slicing: only the base portion of a derived object will be copied, and the polymorphic behavior will be corrupted. If the class has no data, =delete the copy/move functions. Otherwise, make them protected.

The way I interpret this is that I should delete my copy/move constructors/assignment operators in the base class, since it has no data members:

class Base {
public:
    Base(const Base&) = delete;
    Base& operator=(const Base&) = delete;
    Base(Base&&) = delete;
    Base& operator=(Base&&) = delete;
    virtual ~Base() = default;

    virtual bool magic() const;

protected:
    Base() = default;
};

class Derived : public Base {
public:
    Derived() = default;
    Derived(int x, double y) : x_(x), y_(y) {};
    Derived(const Derived& d) : Base(), x_(d.x_), y_(d.y_) {};
    ...

    bool magic() const;

private:
    int x_;
    double y_;
}

But doing so, will force me to implement copy/move constructors/assignment operators in my derived class (which is a point with the guideline, I assume). I can come up with no other way than to manually copy all the data members of my derived class, which seems quite bloated. If I add a new data member and forget to update my copy/move functions, they will break.

Is there an easier way to define copy/move constructors/assignment operators in my derived class, when they are deleted in the base class? And what is the best practice in this situation?

EDIT:

As pointed out in the comments, the copy/move constructors/assignment operators should not be public in the derived class either, according to the same guideline. But the problem remains when defining them as protected.

  • 2
    Making the copy/move constructors/operator= in the base class `protected` is sufficient to prevent slicing. – Mansoor Dec 13 '21 at 15:28
  • BTW, to follow guideline, `Derived`'s copy constructor should be protected. – Jarod42 Dec 13 '21 at 15:40
  • @Jarod42 I don't see how that would help, given that the OP wants to make his derived class copyable. – Paul Sanders Dec 13 '21 at 15:42
  • If you don't need to do anything special in your derived class i.e. just performing member wise copy or move then you should be able to = default them in your derived class and be fine. – Eric Dec 13 '21 at 15:48
  • 1
    @PaulSanders: So OP wants to respect guideline, but also violate it... – Jarod42 Dec 13 '21 at 16:11
  • @Jarod42 you have a valid point there... I guess the guidelines wants you to copy polymorphic classes with a clone method. The problem still remains, how do you implement the (protected) copy/move in the derived class in the best way? – user3242169 Dec 13 '21 at 16:24
  • 1
    @user3242169: I would say `protected` `= default;` since `Base`. – Jarod42 Dec 13 '21 at 16:29
  • Defining them =default in the derived class will compile fine, but cause an error if you actually use them, see https://stackoverflow.com/questions/55007528/is-deleting-copy-and-move-constructors-assignment-operators-in-base-class-enough – user3242169 Dec 13 '21 at 16:36
  • @Jarod Well, they're only _guidelines_, they're not a mantra for success. – Paul Sanders Dec 13 '21 at 16:41

0 Answers0