-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is rule C.67 too inflexible? #1151
Comments
It would be nice to have a concrete counterexample to C.67 where a derived class wants to copy for a good reason. |
I certainly want to be able to copy a Circle even if it is derived from a IShape and considering that a circle is probably just 3 doubles (center & radius) I prefer to not use clone for that (which requires a dynamic memory allocation an returns either a raw pointer or a smart_pointer to the base class) if it isn't necessary. |
Mike, could you elaborate on that example? Starting with
Does Then
How would you write those functions? What would they do? Then finally:
Would |
What I said was meant in support of what jwakely suggested: protected copy construction/assignment should be allowed. Now if you really want to do public implementation inheritance you can solve that problem via another level of indirection:
My general rule of thumb is: Don't inherit publicly from classes with public constructors or assignment operators and vice versa, mark any class with public constructors final. Regardingthe polymorphic types, I think it is important to realize two distinct cases: In the one case, the object is created by some factory on the heap and only ever accessed through the base class interface. In that case, there is obviously no real need for copy constructors and such . The other case however is, where the object is treated just like an normal object in one part of the program (created on the stack, copied around, accessed through expressions of the "correct" dynamic type), but is then presented through a polymorphic interface to another part |
Back to Jonathan's original question: Should protected copying be allowed for a base class? We think the answer is no: Since there will already be a clone function, the derived implementation can already access that and any copying would be in addition and duplicative. Also, as a general principle we are trying to make the guidelines restrict what is possible in the language rather than support every coding style. Does that make sense? |
How does the base classe's clone function solve that problem? The base version's clone function will create a dynamically allocated base class object. How can you turn that into a derived object after the fact? Could you demonstrate how you would do it? Even worse: If my base class is an abstract class, it can't even implement clone in the first place. I certainly don't have knowledge about a representative c++ code base with millions and millions of lines of code, but my feeling is that what you call "[not] support every coding style" effectively outlaws a lot of established practice (of course some people consider dynamic polymorphism the work of the devil so restricting it might be exactly what you want). |
Update from 4/16 editors call: @MikeGitb That's a good point. We will think more about this question. |
Any update on this? |
Stumbled upon this as well. See also: |
Editors call: Sorry for the lag -- we agree with Jonathan and have updated C.67 and C.130 to say that base class copy constructors should be nonpublic. They can be |
I am also wondering whether there should be an ‘exception’ regarding abstract classes. If a class has pure virtual functions, is it still necessary to declare copy operations at all? Technically, it is not necessary, as slicing cannot happen. I.e., I prefer class Serializable {
public:
virtual ~Serializable() = default;
virtual void Serialize(vector<byte>& buffer) = 0;
}; to class Serializable {
public:
virtual ~Serializable() = default;
virtual void Serialize(vector<byte>& buffer) = 0;
protected:
Serializable(const Serializable&) = default;
Serializable& operator=(const Serializable&) = default;
}; |
C.67 A base class should suppress copying, and provide a virtual clone instead if "copying" is desired
That rule requires deleting all the copy/move ops, but is that rule too strong? Isn't it OK to make them protected, so only derived classes can copy/move the base class?
Or even if the derived type isn't copyable and provides a
D::clone()
member as per C.67, the base class' copy constructor can still be useful to implement that (if a copy is made inside theD::clone()
override).Alternatively, if the base is an abstract class then it can't be sliced anyway (and also can't define a sensible
clone()
function so it has to be pure virtual).Maybe the enforcement could be improved, so that it's OK to have copy/move ops if they are protected, or if the class is abstract.
The text was updated successfully, but these errors were encountered: