Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Often times it's a good idea to have an abstract base class to isolate the interface of the object.

The problem is that copy construction, IMHO, is pretty much broken by default in C++, with copy constructors being generated by default.

So, what are the gotchas when you have an abstract base class and raw pointers in derived classes?

class IAbstract
{
    ~IAbstract() = 0;
}

class Derived : public IAbstract
{
    char *theProblem;
    ...
}

IAbstract *a1 = new Derived();
IAbstract a2 = *a1;//???

And now do you cleanly disable copy construction for the whole hierarchy? Declare copy construction as private in IAbstract?

Are there any rules of three with abstract base classes?

share|improve this question
1  
use references instead of pointers :) –  tp1 Mar 11 '12 at 23:34
    
@tp1: or some smart pointer at least. –  Benjamin Bannier Mar 11 '12 at 23:56
    
Sometimes you just have to work with existing code... You can't change everything in an instant. –  Coder Mar 12 '12 at 0:08
    
Why do you think the default copy constructor is broken? –  BЈовић Mar 12 '12 at 9:08
    
Yes, because if you forget to explicitly disable it, the most likely outcome is that the first copy of the class will have unintended consequences. There is a reason Google suggests disabling them: google-styleguide.googlecode.com/svn/trunk/… –  Coder Mar 12 '12 at 9:17

3 Answers 3

up vote 4 down vote accepted

Copy construction on an abstract class should be made private in most cases, as well as assignment operator.

Abstract classes are, by definition, made to be a polymorphic type. So you don't know how many memory does your instance use, and so cannot copy or assign it safely. In practice, you risk slicing : http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c

Polymorphic type, in C++, mustn't be manipulated by value. You manipulate them by reference or by pointer (or any smart pointer).

This is the reason why Java has made object manipulable by reference only, and why C# and D has the separation between classes and structs (the first one being polymorphic and reference type, the second one being non polymorphic and value type).

share|improve this answer
    
Things in Java aren't any better. In Java it's painful to copy anything, even when you really, really need to, and very easy to forget to do it. So you end up with nasty bugs where two data structures have a reference to the same value class (e.g. Date), and then one of them changes the Date and the other data structure is now broken. –  kevin cline Mar 12 '12 at 6:00
    
Meh. It's a non-problem- anybody who knows C++ won't make this mistake. More importantly, there's no reason at all to manipulate polymorphic types by value if you know what you're doing. You're initiating a total knee-jerk reaction over a technically slim possibility. NULL pointers are a bigger problem. –  DeadMG Mar 12 '12 at 12:34

You could, of course, just make it protected and empty, so that derived classes can choose. However, more generally, your code is forbidden anyway because it's impossible to instantiate IAbstract- because it has a pure virtual function. As such, this is generally a non-issue- your interface classes can't be instantiated and therefore can never be copied, and your more derived classes can ban or keep copying as they wish.

share|improve this answer
    
And what if there is a Abstract -> Derived1 -> Derived2 hierarchy, and Derived2 is assigned to Derived1? These dark corners of the language still surprise me. –  Coder Mar 12 '12 at 0:35
    
@Coder: That's usually viewed as PEBKAC. However, more directly, you could always declare a private operator=(const Derived2&) in Derived1. –  DeadMG Mar 12 '12 at 0:36
    
Ok, maybe this really is not an issue. I just want to make sure the class is safe against abuse. –  Coder Mar 12 '12 at 0:40
    
And for that you should get a medal. –  World Engineer Mar 12 '12 at 1:11
1  
@Coder: Abuse by whom? The best you can do is make it easy to write correct code. It's pointless to try to defend against programmers who don't know C++. –  kevin cline Mar 12 '12 at 5:58

By making ctor and assignment private (or by declaring them as =delete in C++11) you disable copy.

The point here is WHERE you have to do that. To stay with your code, IAbstract is not an issue. (note that doing what you did, you assign the *a1 IAbstract subobject to a2, loosing any reference to Derived. Value assignment is not polymorphic)

The issue comes with Derived::theproblem. Copying a Derived into another may in fact share the *theproblem data that may be not designed to be shared (there are two instances that may call delete theproblem in their destructor).

If that's the case, it is Derived that must be non-copyable and not assignable. Of course, if you make private the copy in IAbstract, since the default copy for Derived needs it, Derived will also be not copyable. But if you define your own Derived::Derived(const Derived&) without calling IAbtract copy, you can still copy them.

The problem is in Derived, and the solution must stay into Derived: if it must be a dynamic-only object accessed only by pointers or references, it is Derived itself that must have

class Derived
{
    ...
    Derived(const Derived&) = delete;
    Derived& operator=(const Derived&) = delete;
};

Essentially it is up to the designer of the Derived class (that should know how Derived works and how theproblem is managed) to decide what to do with assignment and copy.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.