12

Is a public constructor in an abstract class a codesmell? Making the constructor protected provides all of the access of which you could make any use. The only additional access that making it public would provide would be to allow instances of the class to be declared as variables in scopes that cannot access its protected members, but instances of abstract classes cannot be declared at all.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
TheBeardyMan
  • 829
  • 10
  • 28
  • How can you declare variables of an abstract class? Am I missing something? – sbi Sep 01 '09 at 16:08
  • I think the OP means methods, as in `protected member methods.` – quamrana Sep 01 '09 at 21:29
  • I still don't get it. Could you show an example? – sbi Sep 02 '09 at 09:22
  • @sbi: Edited my answer to show some of the issues with code. – quamrana Sep 03 '09 at 21:25
  • @quamrana: I might be dense, but I still don't see how a public ctor in an abstract class "allow instances of the class to be declared as variables in scopes that cannot access its protected members" -- or even what that means. – sbi Sep 04 '09 at 09:01
  • Be careful though to explicitly declare/define your protected/private copy constructor. If you don't the compiler will do it for you. See scott meyers [effective c++](http://www.aristeia.com/books.html) item 6. – count0 Sep 01 '09 at 15:48

7 Answers7

13

I've read it in at least one coding guideline that constructors of abstract classes should not be public - I think that rule makes sense for the reason you gave.

However, i can't imagine a scenario where making it public would make things go wrong. So i wouldn't go so far as saying it's a code smell. I see the protected constructor as a "nice to have" property :)

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 2
    Agree, the protected constructor explicits the fact that the class cannot be directly instantiated, so it is a "nice property" from the programmer point of view, even if the compiler does not really care about it. – David Rodríguez - dribeas Sep 01 '09 at 20:42
  • 2
    Coding guidelines are supposed to protect you from bad things that could happen. As you can not instanciate an abstract class I don't see what this guideline is protecting you from and thus feels arbitory. – Martin York Sep 01 '09 at 22:34
  • They say by making it protected, you make it explicit that it cannot be used by derived classes. I suspect that it's a similar rationale as with member operator new and delete: They are implicitly static members, but it's good to make them explicitly static. On the other side, in-class definition of member functions are implicitly inline, and i would say it's poor to make them explicitly inline. In the end, i think this protected-constructor issue is rather a matter of taste. – Johannes Schaub - litb Sep 01 '09 at 22:47
  • Public constructors in abstract classes breaks the default operation of `swig`. – Dave Apr 18 '13 at 17:17
4

My opinion would be that the public constructor might be seen to be confusing, and as you say making it protected would be correct. I would say that a protected constructor correctly reinforces the impression that the only sensible use of an abstract class is to derive from it.

In fact, you only need to declare a constructor in an abstract class if it needs to do something, eg. initialise its own private members. I would then expect there to be other protected member functions that are helpful to derived classes.

EDIT:

Since no-one has posted any code and @sbi asked for some in a comment to OP, I thought I would post some:

class Base:
{
public:           // The question is: should the ctor be public or protected?
// protected:
    Base():i(0){} // ctor is necessary to initialise private member variable
public:
    virtual ~Base(){} // dtor is virtual (but thats another story)
                  // pure virtual method renders the whole class abstract
    virtual void setValue(void)=0;  
protected:
    int getValue(void){ return i;}
private:
    int i;
};

Base b1;  // Illegal since Base is abstract, even if ctor is public
Base& b2=makeBase();  //We can point to, or refer to a Base
b2.setValue();    // We're not sure what this does, but we can call it.
b2.getValue();    // Illegal since getValue is protected
quamrana
  • 37,849
  • 12
  • 53
  • 71
3

As you say, there is no need to provide public constructor of abstract class, nor it can be misused, if you provide public constructor.

However, you may consider declaring constructor as public as recomendation for structuring classes derived from the abstract one.

Nemanja Boric
  • 21,627
  • 6
  • 67
  • 91
  • 3
    Can you explain your second sentence? I don't understand what the recommendation might be. – quamrana Sep 01 '09 at 15:54
  • 1
    I think public ctors will recommend implementing classes a means of designing the public interface. Like, an abstract "Window" class could have a public ctor that has a parameter "Window *parent". It will recommend deriving classes to provide it as a public constructor too, which will be part of the interface. – Johannes Schaub - litb Sep 01 '09 at 15:58
  • I thought that might be the case - I'd say that its wrong. I would say that in the case of a ctor, it should be protected and take the parameters it needs, quite independently of what derived classes should do. Any other public pure virtual member functions, however, **should** be a strong indication that a leaf class needs to implement these with (obviously) the same access level and parameters. – quamrana Sep 01 '09 at 16:15
3

Abstract class can never be directly instantiated because of the pure virtual methods it declares. So, declaring constructor as protected is just adds additional tips for programmers.

I saw recommendation to declare constructor as protected here, in Google style guide. And I've met similar recommendations in some other corporate coding standards. So this is looks like a good practice.

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212
2

I'd say its a bad sign for a couple of reasons.

The first is that it might mislead somebody into thinking they can actually call that routine.

The second is that it implies the author thought you could call it. You now don't know if that was an important part of his design or not.

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
  • 2
    I don't think those are valid arguments. No one who knows the first thing about OO design or C++ would think that you could call it and second of all the compiler will give an error the moment you try. – Robert S. Barnes Sep 01 '09 at 17:23
2

I know that allot of people obviously disagree, but I don't think an abstract classes ctor should be protected unless the interface you are designing has a specific reason for all derived classes to also have a protected ctor.

The reason is that when you design an abstract class you're designing an interface to be implemented by the deriving classes. Derived classes should implement the interface exactly as it's designed in the base class. The interface presented by an abstract base class is a contract; don't break that contract.

Or in other words, if you're changing the interface, why are you deriving from that class in the first place?

This is a bit of a religious answer, but what the heck. ;-)

Robert S. Barnes
  • 39,711
  • 30
  • 131
  • 179
  • 1
    @Robert: I understand your reason given here, but I believe that it does not apply to the ctor. Yes, other public and protected member functions (excluding the ctor and dtor) provide interfaces that are a contract and you should think twice before changing them. – quamrana Sep 01 '09 at 21:36
2

Answer for Modern C++

I'm bumping an old thread here, however:

  • this is the first question that came up for me when searching for the difference between public and protected constructors in abstract classes,
  • the new C++ standards published after this question was asked and answered change the "correct" answer.

Summary

public constructors in abstract classes are not a code smell. Due to the way access modifiers of inherited constructors work, having a public vs protected constructor is not equivalent. public constructors in abstract classes add more access rights than protected ones.


Explanation

The standard draft N4659, 10.3.3/19 specifies that:

A synonym created by a using-declaration has the usual accessibility for a member-declaration. A using-declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored.

This behavior was introduced together with using-declarators in C++11, see this question for more details.

Here is a minimal example [godbolt]:

class AbstractPublicCtor {
public:
    virtual void foo() = 0;
    AbstractPublicCtor(int) {}
};

class AbstractProtectedCtor {
public:
    virtual void foo() = 0;
protected:
    AbstractProtectedCtor(int) {}
};

class PublicCtor : public AbstractPublicCtor {
public:
    using AbstractPublicCtor::AbstractPublicCtor;
    void foo() override {}
};

class ProtectedCtor : public AbstractProtectedCtor {
public:
    using AbstractProtectedCtor::AbstractProtectedCtor;
    void foo() override {}
};

int main() {
    PublicCtor x(5);  // works
    ProtectedCtor y(6); // fails to compile 
}

Rule of thumb

  • Use public constructors if the implementers of the abstract class should have public constructors, and the base class constructor is a suitable candidate for a public constructor of the implementer.
  • Otherwise, use protected constructors (e.g. when the implementers are constructed using a factory).

Note: This is my personal opinion, I'm happy to discuss it in the comments.

gflegar
  • 1,583
  • 6
  • 22
  • I disagree with the rule of thumb and summary, because it only applies when the derived classes don't use own constructor specializations and it seems more readable to have the constructor protected and don't use "using", I would say that using "using" in combination with the "AbstractPublicCtor" is code smell, too. When the constructor is supposed to be callable only from the derived classes, I would make it protected so the intention is clear. – Lukas Salich Apr 03 '19 at 16:11