简体   繁体   English

当基类构造函数受保护时,在派生类成员函数中创建基类实例

[英]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. 如果将基类A构造函数更改为public ,则代码将编译。 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 . B的成员内,您只能通过B类型的对象访问A受保护成员。 So you can't access the protected default constructor there. 因此,您不能在那里访问受保护的默认构造函数。

The previous line A a(); 前一行A a(); compiles because it declares a function. 编译是因为它声明了一个函数。

§11.4/1: §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 . 如前所述,授予访问受保护成员的权限,因为该引用发生在某个C类的朋友或成员中。 If the access is to form a pointer to member (5.3.1), […]. 如果访问要形成指向成员(5.3.1)的指针,则[…]。
All other accesses involve a (possibly implicit) object expression (5.2.5). 所有其他访问都涉及一个(可能是隐式的)对象表达式(5.2.5)。 In this case, the class of the object expression shall be C or a class derived from C . 在这种情况下,对象表达式的类应为C或从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 . 我们正在尝试使用(隐式)对象参数a1访问A s的构造函数。 §11/6: §11/ 6:

All access controls in Clause 11 affect the ability to access a class member name from the declaration of a particular entity […]. 第11章中的所有访问控制都会影响从特定实体的声明中访问类成员名的能力[…]。 [ 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 . 但是, a1不是B型或从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 . 要允许访问受保护的方法,可以使用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. 当您有任何具有受保护的或私有的Constructor的类时,该类将被视为“抽象类对象”,这意味着它表示一个概念或概念,该概念应该是什么样的对象,其中包含所有注释元素。 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. A和D类不能实例化对象,但是B,C,E和F类可以实例化对象。 Because the constructors for A & D are protected any derived class has access to them. 因为A&D的构造函数受到保护,所以任何派生类都可以访问它们。 With this setup every class has access to A::cleanup() and every class must implement its own ::initialize() override function. 使用此设置,每个类都可以访问A :: cleanup(),并且每个类都必须实现自己的:: initialize()覆盖函数。

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. 在这种情况下,仅作为演示,Counter类的唯一目的是进行增量工作。 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. 计数器类不能是没有意义的独立对象,但是通过在其他类中通过friend声明可以使用这些计数器,这些计数器类可以通过声明为外部类的函数声明通过函数声明访问其构造函数朋友函数在抽象类中。 This kind of setup allows only Object1::getCount() and Object2::getCount() to declare a type of Counter and to have access to Counter::getCounter(). 这种设置仅允许Object1 :: getCount()和Object2 :: getCount()声明计数器的类型并可以访问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(); 在您的代码中其他人解决了AA()的问题; is declaring a function prototype where A a1; 在声明一个函数原型,其中A a1; is trying to declare a type of A which is Abstract! 试图声明A的类型为Abstract!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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