3

i'm trying to figure out the difference between public constructor and protected constructor for an abstract base class. Let's say that i have two classes:

Abstract Base Class: Monster

class Monster
{
public: // or protected?? what is the techincal difference?
    Monster(string name)
    {
        _name = name;
    }
public:
    virtual void attack() = 0;

    const string getName() const
    {
        return _name;
    }

private:
    string _name;

};

Concrete Child Class: Spider

class Spider : public Monster
{
public:
    Spider(string name) : Monster(name)
    {

    }

    void attack() override
    {
        cout << getName() << ":(Spider) is attacking!" << endl;
    }
};

Now if i try to create a Monster instance:

int main()
{
    Monster monster1 { "Abstract Monster Not Allowed" }; // Error
}

Error: Object of abstract class type "Monster" not allowed: Monster:: Attack is a pure virtual function.

This perfectly makes sense, but so a 'public constructor' is an alias of 'protected constructor' in an abstract class? In which situation I could use protected constructor for an abtract class?

Thanks in advance.

chrk
  • 4,037
  • 2
  • 39
  • 47

4 Answers4

1

When working with inheritance and abstract base classes, if your base class has a function that is purely virtual virtual void doSomething() = 0;, this means that every class that inherits from this base class must implement this function; also, this base class can not be instantiated since it will be abstract.

When working with constructors for public, protected & private member access will restrict how the class behaves to outside callers. If the constructor is public, then that constructor can be called and an instance of that object can be created, provided the class is not abstract. When a constructor is protected, you can not call the constructor from outside of the class; however, any class that inherits from it can call the protected constructor, unless a friend modifier is used.

This is what it means to be abstract. A base class that is abstract can not be an object, but is an encapsulated concept or idea that contains all of the information that is common between all derived classes. It is a sub-object to an object that can be instantiated.

If you are using a purely virtual method as in this example then the base class can not be instantiated, however if you are using just virtual methods and no purely virtual methods then yes it can be instantiated! But be careful with virtual methods in a base class and calling them within the constructor, they can be dangerous.

I will show a simple sample of an abstract base class with both public & protected constructors. The first case will be with a public constructor:

class Animal {
public: 
    enum AnimalType {
        AMPHIBIAN,
        BIRD,
        FISH,
        MAMMAL,
        REPTILE,
     }; // AnimalType
        
protected:
    AnimalType m_type;
    int m_age;
    float m_weight;

    std::string m_strVoice;

public:
    Animal( AnimalType type, int age, float weight ) :
        m_type( type ), m_age( age ), m_weight( weight )
    {}

    virtual ~Animal() {}  // Virtual Due To Inheritance
    
    AnimalType getType() const { return m_type; }

    void setAge( int age ) { m_age = age; }
    int  getAge() const { return m_age; }

    void setWeight( float weight ) { m_weight = weight; }
    float getWeight() const { return m_weight; }

    virtual std::string speak() = 0; // Purely Virtual All Derived Class Must Implement This
    // Abstract Class Can Not Be Instantiated

}; // Animal

class Dog : public Animal {
public:
    Dog( int age, float weight ) : Animal( AnimalType::MAMMAL, age, weight ) {}

    virtual ~Dog() {}

    std::string speak() { return std::string( "rough" ); }

}; // Dog

With this structure you can create only the Dog object somewhere else in your source code.

Now to demonstrate a protected constructor using the same example above:

class Animal {
public: 
    enum AnimalType {
        AMPHIBIAN,
        BIRD,
        FISH,
        MAMMAL,
        REPTILE,
     }; // AnimalType
        
protected:
    AnimalType m_type;
    int m_age;
    float m_weight;

    std::string m_strVoice;

public:
    virtual ~Animal() {}  // Virtual Due To Inheritance
    
    AnimalType getType() const { return m_type; }

    void setAge( int age ) { m_age = age; }
    int  getAge() const { return m_age; }

    void setWeight( float weight ) { m_weight = weight; }
    float getWeight() const { return m_weight; }

    virtual std::string speak() = 0; // Purely Virtual All Derived Class Must Implement This
    // Abstract Class Can Not Instantiate

protected:
    Animal( AnimalType type, int age, float weight ) :
        m_type( type ), m_age( age ), m_weight( weight ) {}
    // Constructor Is Protected - Doesn't Necessarily Make It Abstract
    // But Prevents Outside Code From Accessing This Constructor Only
    // Allowing Either Derived Classes Or Friends To Access This Constructor 

}; // Animal

class Mammal : public Animal {
public:
    virtual std:string speak() = 0;
protected:
    Mammal( int age, float weight ) : Animal( AnimalType::MAMMAL, age, weight ) {}     

}; // Mammal

class Dog : public Mammal {
public:
    Dog( int age, float weight ) : Mammal( age, weight ) {}

    virtual ~Dog() {}

    std::string speak() { return std::string( "rough" ); }

}; // Dog

In the second case here, both Animal & Mammal can not be constructed as an object from somewhere else but Dog can. This is due to the protected constructor. Here both Animal & Mammal represent a concept & not an object, but Dog does represent an object. I hope this helps you.

underscore_d
  • 6,309
  • 3
  • 38
  • 64
Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • This is not correct! I know the 'abstract' concept, but in your example, you CAN NOT create object of Animal although it has a public constructor! My question is: knowing that abstract class with at least one purely virtual function CAN NOT be instantiated (it results in a compile error), what is the benefit to make the abstract class constructor protected? In both cases (public or protected constructor of abstract class with a purely virtual function) you CAN NOT create object of that abstract type. Demonstration: [ERROR-Demostration](http://puu.sh/jM2p6/b8f73bc9c0.png) – Giuseppe Ruggeri Aug 23 '15 at 21:53
  • You are right, sorry about that I was using a purely virtual function in the base class, not just a virtual function! – Francis Cugler Aug 24 '15 at 07:44
  • If you know that your base class is going to have a purely virtual methods where the class can not be instantiated, then it is good to have a protected constructor so that only the derived classes have access to it! – Francis Cugler Aug 24 '15 at 07:45
  • Also if you have a base class that has a private constructor then your derived class will need to have the friend modifier to their classes to gain access to the private constructor. – Francis Cugler Aug 24 '15 at 07:50
  • I don't know the technical details of how the compiler interprets this at the machine level, but what I do know is that when it comes to public, protected & private they are access modifiers for both classes & structures. Think of a public versus protected function and who has access to those functions, well your constructor is a function! Even though it is a special function! It still works the same way! ... – Francis Cugler Aug 24 '15 at 08:10
  • (...continued) think of it this way, let's say you have a base class that is not abstract (no purely virtual methods). If your constructor is public then any other class or function can access it directly, when you make the constructor protected then only derived classes have access to it unless you associate other class or functions with it by using the friend access modifier. If you make the constructor private and you want something to access it then the friend modifier is a must! Now apply these same guidelines to an abstract class! – Francis Cugler Aug 24 '15 at 08:13
  • As far as I know when a base class is abstract there is no major difference between a public or a protected constructor. Only that the compiler sets the access level of that constructor according to your declaration. – Francis Cugler Aug 24 '15 at 08:25
  • Here is a link to a discussion about constructor access levels & abstract classes. http://bytes.com/topic/c/answers/806186-purpose-protected-constructors – Francis Cugler Aug 24 '15 at 08:48
  • I also edited my initial answer to reflect the correct usage of the language. I typed this freehand from the site before trying it in my compiler. – Francis Cugler Aug 24 '15 at 09:04
  • Also if you do not have a purely virtual function in your base class, but you do have a protected constructor this does not make the base class abstract. It only makes the constructor inaccessible from outside of itself or its derived members. When you are writing class hierarchies and you have a base class that you know you do not want it to be instantiated because there isn't enough information upon construction either it be an abstract base class or not, using a protected constructor hides the constructor from the public interface! – Francis Cugler Aug 24 '15 at 09:08
1

Think of a coin as being an abstract base class. You do not want to instantiate a coin object directly, but you will want to construct derived types of coins that have different attributes such as Country of Origin, Face Value and then set the properties accordingly such as the size, weight and material they are made of. We don't want to have a bunch of coin base classes laying around in some container because there isn't enough of information to describe that coin object. Therefore this coin object is abstract or is a concept. However the derived objects of this coin base class such as an American Silver Dollar, or A German Franc etc., are real objects that can be instantiated since they are real objects and enough information is known about them while constructing them.

Due to the nature of this and due to how class encapsulation works even if the base class is not abstract meaning there is no need for purely virtual functions then the coin base class's constructor should be protected! Even if you do have the need for purely virtual methods within this coin class it is still good practice to keep the constructor protected. This makes the source more readable to others when they are looking at your class interface and they see a protected constructor. They know that this class can not be directly instantiated.

Now let us say that another class has the relationship of has a "coin" class such as a bank class or a mint class where the mint class creates the coins & the bank class holds the coins, it is possible that these classes could have the friend access modifier to the protected coin constructor so that they can create instances of these coins before any information is available and store them into containers to later be processed. Think of this as a pre-batch operation and with this layout the coin base class serves as a template (not a c++ programming template).

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59
  • Thanks, very clarifier comment, i don't know why should i need to instantiate with friend modifier the abstract Coin (always if it has not purely virtual functions).. if in the bank class i create a Coin (abstract object), after i will have to destroy that object and reinitialize or plus correctly repoint to the new Specialized concrete class.. – Giuseppe Ruggeri Aug 24 '15 at 16:49
1

A protected constructor in an abstract class can only be invoked in the process of constructing an instance of a derived class.

However, your error message in main() has nothing to do with the constructor being protected. It is because an abstract class (with at least one function declared as pure virtual, as you are doing with virtual void attack() = 0) cannot be instantiated, regardless of what constructors it has and regardless of accessibility (protected, public, or private) of those constructors.

A derived class also cannot be instantiated unless it overrides all pure virtual functions it inherits. If it overrides all inherited pure virtual functions (and doesn't declare any of its own functions to be pure virtual) it can be instantiated.

Peter
  • 35,646
  • 4
  • 32
  • 74
0

In C++, public class members are accessible from everywhere, but protected members are only accessible from a derived class. Private members are only accessible from the class itself, so any derived class cannot access them.

Here is more info about protected constructors.

Community
  • 1
  • 1