受保护字段的细微C++继承错误
subtle C++ inheritance error with protected fields
下面是访问实例的受保护字段 x 的简单示例。B 是 A 的子类,因此 B 类型的任何变量也是 A 类型。为什么 B::foo(( 可以访问 b 的 x 字段,而不能访问 a 的 x 字段?
class A {
protected:
int x;
};
class B : public A {
protected:
A *a;
B *b;
public:
void foo() {
int u = x; // OK : accessing inherited protected field x
int v = b->x; // OK : accessing b's protected field x
int w = a->x; // ERROR : accessing a's protected field x
}
};
这是我在使用 g++ 时遇到的错误
$ g++ -c A.cpp
A.cpp: In member function ‘void B::foo()’:
A.cpp:3: error: ‘int A::x’ is protected
A.cpp:14: error: within this context
由于B
是从A
公开继承的,因此 A 的受保护成员成为 B 的受保护成员,因此 B 可以像往常一样从其成员函数访问其受保护成员。也就是说,B
的对象可以从其成员函数访问B
的受保护成员。
但是 A 的受保护成员不能在类外部访问,使用 A
类型的对象。
以下是标准(2003(的相关文本
11.5 受保护的成员访问 [类受保护]
当派生类的友元或成员函数引用基类的受保护的非静态成员函数或受保护的非静态数据成员时,除了前面的条款 11.102 中所述的内容外,还适用访问检查(除非形成指向成员的指针 (5.3.1(,否则访问必须通过指向派生类本身(或从该类派生的任何类(的指针、引用或对象 (5.2.5(。如果访问要形成指向成员的指针,则嵌套名称说明符应命名派生类(或任何 类派生自该类(。
该示例来自标准(2003(本身:
[Example:
class B {
protected:
int i;
static int j;
};
class D1 : public B {
};
class D2 : public B {
friend void fr(B*,D1*,D2*);
void mem(B*,D1*);
};
void fr(B* pb, D1* p1, D2* p2)
{
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // OK (access through a D2)
p2->B::i = 4; // OK (access through a D2, even though naming class is B)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK (type of &D2::i is int B::*)
B::j = 5; // OK (because refers to static member)
D2::j =6; // OK (because refers to static member)
}
void D2::mem(B* pb, D1* p1)
{
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
i = 3; // OK (access through this)
B::i = 4; // OK (access through this, qualification ignored)
int B::* pmi_B = &B::i; // ill-formed
int B::* pmi_B2 = &D2::i; // OK
j = 5; // OK (because j refers to static member)
B::j = 6; // OK (because B::j refers to static member)
}
void g(B* pb, D1* p1, D2* p2)
{
pb->i = 1; // ill-formed
p1->i = 2; // ill-formed
p2->i = 3; // ill-formed
}
—end example]
注意在上面的例子中fr()
是D2
的友元函数,mem()
是D2
的成员函数,g()
既不是友元函数,也不是成员函数。
考虑:
class A {
protected:
int x;
};
class C : public A
{
};
class B : public A {
protected:
unique_ptr<A> a;
public:
B() : a(new C) // a now points to an instance of "C"
{ }
void foo() {
int w = a->x; // B accessing a protected member of a C? Oops.
}
};
在公共继承中:
基类的所有Public members
都成为派生类
的Public Members
基类的所有Protected members
都成为Derived Class
的Protected Members
。
根据上述规则:
受保护成员x
从A
成为类 B
的受保护成员。
class B
可以在其成员函数foo
中访问自己的受保护成员,但它只能访问派生它的A
的成员,而不是所有类A
。
在这种情况下class B
包含一个A
指针a
,它无法访问这个包含的类的受保护成员。
为什么B::foo()
可以访问包含的class B
指针b
的成员?
规则是:
在C++访问控制基于每个类而不是基于每个对象工作。
因此,class B
的实例将始终可以访问另一个class B
实例的所有成员。
演示规则的代码示例:
#include<iostream>
class MyClass
{
public:
MyClass (const std::string& data) : mData(data)
{
}
const std::string& getData(const MyClass &instance) const
{
return instance.mData;
}
private:
std::string mData;
};
int main() {
MyClass a("Stack");
MyClass b("Overflow");
std::cout << "b via a = " << a.getData(b) << std::endl;
return 0;
}
为什么 B::foo(( 可以访问 b 的 x 字段,而不能访问 a 的 x 字段?
受保护的成员只能由同一类(或派生类(的其他成员访问。
b->x
指向类 B 实例的受保护成员(通过继承(,因此B::foo()
可以访问它。
a->x
指向类 A 实例的受保护成员,因此B::foo()
无法访问它。
B
与类A
不同。这就是为什么类 B
的成员无法访问类 A
的非公共成员。
另一方面,类B
公开派生自类A
,所以类B
现在有一个(受保护的(成员x
,任何类B
的成员都可以访问。
让我们从基本概念开始,
class A {
protected:
int x;
};
class B : public A {
public:
void foo() {
int u = x; // OK : accessing inherited protected field
}
};
由于 child 继承了父项,因此 child 得到 x.因此,您可以直接在 child 的 foo(( 方法中访问 x。这就是受保护变量的概念。您可以直接访问子级中父级的受保护变量。注意:这里我说的是你可以直接访问x,但不能通过A的对象!有什么区别?由于 x 是受保护的,因此您无法在 A 之外访问 A 的受保护对象。这就是为什么您无法通过以下方式访问的原因
class B : public A {
protected:
A *a;
public:
void foo() {
int u = x; // OK : accessing inherited protected field x
int w = a->x; // ERROR : accessing a's protected field x
}
};
这里有一个有趣的概念。您可以使用类中的对象访问类的私有变量!
class dummy {
private :
int x;
public:
void foo() {
dummy *d;
int y = d->x; // Even though x is private, still you can access x from object of d - But only with in this class. You cannot do the same outside the class.
}
};
受保护的变量也是如此。因此,您可以访问以下示例。
class B : public A {
protected:
A *a;
B *b;
public:
void foo() {
int u = x; // OK : accessing inherited protected field x
int y = b->x; // OK : accessing b's protected field x
int w = a->x; // ERROR : accessing a's protected field x
}
};
希望它能解释:)
C++是完整的面向对象编程,而Java是纯面向对象的:)
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何在QT Creator上将QWidget声明为继承类的对象