当基 class 构造函数受保护时,在派生 class 成员函数中创建基 class 实例
Create base class instance in derived class member function when the base class constructor is protected
给定以下代码:
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
}
};
如果我将基础 class A
构造函数更改为 public
,代码将编译。这怎么解释?
为了创建一个对象,这样做所需的构造函数必须是可访问的。在 B
的成员中,您可以通过 B
类型的对象访问 A
的受保护成员,但 只能。所以你不能在那里访问受保护的默认构造函数。
上一行 A a();
可以编译,因为它声明了一个函数。
§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
.
在您的情况下,访问是隐式的,但仍然存在。我们正在尝试使用(隐式)对象参数 a1
访问 A
的构造函数。 §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 ]
但是,a1
不是 B
类型或从 B
派生的 class 类型。因此我们的上述要求不满足,访问控制也不满意。
要允许访问受保护的方法,您可以使用 friend class
。
一个例子:
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;
}
};
当你有任何 class 具有受保护或私有构造函数时,class 被视为 "An Abstract Class Object" 这意味着它代表了一个概念或一个对象应该是什么的想法就像包含所有评论元素一样。你不能直接实例化这个类型的对象!因此你必须从这个 class 继承谁的构造函数是 public 除非它们也是抽象的。另一个想法是成为一个不能直接实例化的专用对象,但可以成为其他 classes 的朋友,他们的方法可以实例化该对象,这意味着那些 classes 可以访问这个抽象class 将能够实例化此对象,该对象将存在于 friends class 对象的生命周期和范围内。示例:
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;
};
这里我演示多态继承。 Class A & D 你不能实例化对象,但是 classes B,C,E & F 你可以实例化对象。因为 A 和 D 的构造函数受到保护,任何派生的 class 都可以访问它们。使用此设置,每个 class 都可以访问 A::cleanup() 并且每个 class 都必须实现自己的 ::initialize() 覆盖函数。
对于下一部分,我将演示如何使用 class 朋友可以使用的抽象 class。
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; }
};
此代码展示了如何使用无法单独声明但可以通过成为朋友 class 在其他 class 中使用的抽象 class。在这种情况下,仅作为演示,Counter class 的唯一目的是进行递增工作。计数器 class 不能是没有意义的独立对象,但是通过友元声明在其他 classes 中使用它允许那些 classes 访问它的构造函数通过外部 classes 的函数声明在抽象 class 中声明为友元函数。这种设置只允许 Object1::getCount() 和 Object2::getCount() 声明一种计数器类型并访问 Counter::getCounter()。
我希望这有助于您在抽象 Classes 中理解使用继承处理多态性,通过友元使用抽象 Class 关联,以及如何正确声明抽象类型。
在你的代码中,其他人已经解决了 A A();正在声明一个函数原型,其中 A a1;正在尝试声明 A 的类型,它是抽象的!
给定以下代码:
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
}
};
如果我将基础 class A
构造函数更改为 public
,代码将编译。这怎么解释?
为了创建一个对象,这样做所需的构造函数必须是可访问的。在 B
的成员中,您可以通过 B
类型的对象访问 A
的受保护成员,但 只能。所以你不能在那里访问受保护的默认构造函数。
上一行 A a();
可以编译,因为它声明了一个函数。
§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 beC
or a class derived fromC
.
在您的情况下,访问是隐式的,但仍然存在。我们正在尝试使用(隐式)对象参数 a1
访问 A
的构造函数。 §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 ]
但是,a1
不是 B
类型或从 B
派生的 class 类型。因此我们的上述要求不满足,访问控制也不满意。
要允许访问受保护的方法,您可以使用 friend class
。
一个例子:
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;
}
};
当你有任何 class 具有受保护或私有构造函数时,class 被视为 "An Abstract Class Object" 这意味着它代表了一个概念或一个对象应该是什么的想法就像包含所有评论元素一样。你不能直接实例化这个类型的对象!因此你必须从这个 class 继承谁的构造函数是 public 除非它们也是抽象的。另一个想法是成为一个不能直接实例化的专用对象,但可以成为其他 classes 的朋友,他们的方法可以实例化该对象,这意味着那些 classes 可以访问这个抽象class 将能够实例化此对象,该对象将存在于 friends class 对象的生命周期和范围内。示例:
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;
};
这里我演示多态继承。 Class A & D 你不能实例化对象,但是 classes B,C,E & F 你可以实例化对象。因为 A 和 D 的构造函数受到保护,任何派生的 class 都可以访问它们。使用此设置,每个 class 都可以访问 A::cleanup() 并且每个 class 都必须实现自己的 ::initialize() 覆盖函数。
对于下一部分,我将演示如何使用 class 朋友可以使用的抽象 class。
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; }
};
此代码展示了如何使用无法单独声明但可以通过成为朋友 class 在其他 class 中使用的抽象 class。在这种情况下,仅作为演示,Counter class 的唯一目的是进行递增工作。计数器 class 不能是没有意义的独立对象,但是通过友元声明在其他 classes 中使用它允许那些 classes 访问它的构造函数通过外部 classes 的函数声明在抽象 class 中声明为友元函数。这种设置只允许 Object1::getCount() 和 Object2::getCount() 声明一种计数器类型并访问 Counter::getCounter()。
我希望这有助于您在抽象 Classes 中理解使用继承处理多态性,通过友元使用抽象 Class 关联,以及如何正确声明抽象类型。
在你的代码中,其他人已经解决了 A A();正在声明一个函数原型,其中 A a1;正在尝试声明 A 的类型,它是抽象的!