简体   繁体   中英

Create base class instance in derived class member function when the base class constructor is protected

Given the following code:

class A
{
protected:
    A(){};  // compilation error
public:
    void foo(){cout << "A\n";}; 
};

class B : public A
{
public:
    B() { };
    void foo(){
        cout << "B\n";
        A A(); // OK
        A a1; // compilation error
    }
};

If I changed the base class A constructor to public , the code compiles. How to explain this?

In order to create an object, the constructor needed to do so must be accessible. Within a member of B , you can access protected members of A , but only via an object of type B . So you can't access the protected default constructor there.

The previous line A a(); compiles because it declares a function.

§11.4/1:

As described earlier, access to a protected member is granted because the reference occurs in a friend or member of some class C . If the access is to form a pointer to member (5.3.1), […].
All other accesses involve a (possibly implicit) object expression (5.2.5). In this case, the class of the object expression shall be C or a class derived from C .

In your case, the access is implicit but nonetheless present. We are trying to access A s constructor with the (implicit) object argument a1 . §11/6:

All access controls in Clause 11 affect the ability to access a class member name from the declaration of a particular entity […]. [ Note : this access also applies to implicit references to constructors, conversion functions, and destructors. end note ]

However, a1 is not of type B or a class derived from B . Hence our above requirement is not met, and access control is not happy.

To allow access to protected methods you can use friend class . An example:

class A
{
    friend class B;
protected:
    A(){};
public:
    void foo(){cout << "A\n";}; 
};

class B : public A
{
public:
    B() { };
    void foo(){
        cout << "B\n";
        A a1;
    }
};

When you have any class that has a protected or private Constructor, that class is considered "An Abstract Class Object" This means that it represents a concept or an idea of what an object should be like that contains all comment elements. You can not instantiate an object of this type directly! Thus you must inherit from this class who's constructors are public unless if they are abstract as well. The other idea is to be a specialized object that can not be instantiated directly but can be friends to other classes where their methods can instantiate the object, meaning those classes that have friend access to this abstract class would be able to instantiate this object which will live in the life span and scope of the friends class object. Examples:

class A {
public: 
    enum ClassType {
        TYPE_A = 0,
        TYPE_B,
        TYPE_C,
        TYPE_D,
        TYPE_E,
        TYPE_F
    };

private:
    unsigned m_uId;
protected:
    explicit A( A::ClassType type ) :
    m_uId( static_cast<unsigned>( type ) {}

    void initialize() = 0; // Purely Abstract - Each Derived Class Must Create This Function
    void cleanup();     
};

class B sealed : public A {
public:
    B() : A( TYPE_A ) {}
    void initialize() override; 
};

class C sealed : public A {
public:
    C() : A( TYPE_C ) {}
    void initialize() override;
};

class D : public A {
protected:
    D( A::ClassType type ) : A( type ) {}          
    void initialize() override = 0;
};

class E sealed : public D {
public:
    E() : D( TYPE_E ) {}
    void initialize() override;
};

class F sealed : public D {
public:
    F : D( TYPE_F ) {}
    void initialize() override;
};

Here I demonstrate polymorphic inheritance. Class A & D you can not instantiate objects for, however classes B,C,E & F you can instantiate objects. Because the constructors for A & D are protected any derived class has access to them. With this setup every class has access to A::cleanup() and every class must implement its own ::initialize() override function.

For this next part I will demonstrate the use of using an abstract class that friend classes can use.

class Counter {
    friend unsigned Object1::getCount();
    friend unsigned Object2::getCount();
private:
   static unsigned m_uCounter;       
   Counter() { ++m_uCounter; }

public:
    unsigned getCounter() { return m_uCounter; }       
};

class Object1 {
    friend class Counter;
private:
    unsigned m_uCount;
public:
    Object1() : m_uCount( 0 ) {}
    void count() { 
        Counter counter; 
        m_uCount = counter.getCounter();
    }

    unsigned getCount() const { return m_uCounter; }      
};

class Object2 {
    friend class Counter;
private:
    unsigned m_uCount;
public:
    Object2() : m_uCount( 0 ) {}
    void count() {
        Counter counter;
        m_uCount = counter.getCounter();
    }

    unsigned getCount() const { return m_uCount; }
};

This code shows how to use an abstract class that can not be declared on its own, but can be used within other classes by being a friend class. In this situation as only a demonstration the sole purpose of the Counter class is to do the work of incrementing. The counter class can not be a stand alone object which doesn't make sense to have, however its use within other classes through the friend declarations allows those classes to have access to its constructor via the function declaration from the outside classes that are declared as friend functions within the abstract class. This kind of setup allows only Object1::getCount() and Object2::getCount() to declare a type of Counter and to have access to Counter::getCounter().

I hope this helps your understanding in Abstract Classes that deal with Polymorphism using inheritance, Abstract Class association via friend use, and how to properly declare a type that is abstract.

In your code in which others had addressed AA(); is declaring a function prototype where A a1; is trying to declare a type of A which is Abstract!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM