Ast*_*mit 11 c++ public visual-c++ visual-c++-2010 c++11
我有一个基类A和派生类B.
B类是从A公开的
如果A是类a是成员变量,我想访问成员变量的地址
当我使用受保护和公共访问说明符时,我正在观察不同的行为.
在这种情况下,当A类成员a 受到保护时,我得到:
cout<<&A::a << endl; 给我一个编译器错误..
但是cout<<&(A::a)<<endl;有效并给我正确的结果.
在这种情况下,当A级成员a 公开时,我得到:
为什么会这样?
这是完整的代码:
#include <iostream>
using namespace std;
class A
{
    protected:
    int a;
    void fun() 
    {
    cout<<"A's fun"<<endl;
    }
public:
    A(int Aarg):a(Aarg)
    {
        cout << "A's construction done" <<endl;
    }
};
class B: public A
{
protected:
int b;
public:
void fun()
{
cout << "B's fun"<<endl;
}
B(int As, int Bs):A(As), b(Bs)
{
std::cout<<"B's Construction Done" <<std::endl;
}
void show()
{
A::fun();
//cout << a << endl;
cout<<&A::a << endl; //compilation error
}
};
int main()
{
    B(10,20).show();
    return 0;
}
现在有一个我能够观察到的未定义的行为:
如果我在A类中将我的成员变量a作为公共,那么就不会出现任何编译错误,但输出结果为1我不知道为什么..
class A{
public:
int a
....
....
OUTPUT:
A的建设完成了
B的建设完成
一个有趣的
0027F91C
1(为什么1)并且没有我在尝试访问受保护成员时能够获得的错误?
简短回答:不涉及未定义的行为。您看到的行为是:
\n\n&A::a试图获取指向类 A 的成员 a 的成员指针。如果 a 在 A 中受保护,则该表达式仅通过类 A(或 A 的友元)内的访问检查。在从 A 派生的类 B 中,您只能通过表达式获得相同的指向成员的指针&B::a(请注意,该表达式的类型仍然是int A::*)。儿子A::a在 A 中受保护,则&A::a派生类 B 的成员函数中不允许该表达式。这是您的编译器错误。A::a在 A 中是 public,则该表达式有效,生成指向成员的指针。ostream,例如使用cout << &A::awill print 1。这是调用的结果ostream::operator << (bool)。您可以使用 boolalpha 操纵器来查看这确实是所选的重载:cout << boolalpha << &A::awill print true。&(this->a)),它是一个普通的int指针。对 的基类子对象的受保护成员的访问*this是有效的,因此即使 a 在 A 中受保护,也可以使用该变体。更长的解释:
\n\n标准说(5.3.1/3):
\n\n\n\n\n一元 & 运算符的结果是指向其操作数的指针。\n 操作数应为左值或限定 ID。如果操作数是命名某个类型为 T 的某个类 C 的非静态成员 m 的限定 ID,则结果的类型为 \xe2\x80\x9c,指向类型为 T\xe2\x80\ 的类 C 的成员的指针x9d 是指定 C::m 的纯右值。[...]
\n
因此该表达式&A::a尝试获取指向类 A 的成员 a 的成员指针。
在下一段 (5.3.1/4) 中,详细说明了只有 &X::m 语法生成指向成员的指针 - &(X::m)、nor&m或 plainX::m都不会:
\n\n\n仅当使用显式 & 并且其\n 操作数是未括在括号中的限定 ID 时,才会形成指向成员的指针。
\n
但这样的表达式只有在允许访问的情况下才有效。如果是受保护成员 (11.4/1) 适用:
\n\n\n\n\n当非静态数据成员或非静态成员函数是其命名类 (11.2) 的受保护成员时,将应用超出第 11 条前面所述的附加访问检查 (11.2) 如前所述,访问protected 成员被授予,因为引用出现在某个类 C 的友元或成员中。如果访问是为了形成指向成员的指针 (5.3.1),则嵌套名称说明符应表示 C\n 或从 C 派生的类。 [...]
\n
在您的情况下,将授予对受保护成员 a 的访问权限,因为对 a 的引用发生在从 A 派生的类 B 的成员中。当表达式尝试形成指向成员的指针时,嵌套名称说明符(部分最后的“::a”之前)必须表示 B。因此,最简单的允许形式是&B::a。该表格&A::a仅允许在 A 级本身的成员或朋友内部使用。
指向成员的指针没有格式化输出运算符(既不是 istream 成员,也不是自由运算符函数),因此编译器将查看可以使用标准转换(序列)调用的重载。从指针到成员到其他内容的唯一标准转换在 4.12/1 中描述:
\n\n\n\n\n指向成员类型的 [...] 指针的纯右值可以转换为 bool 类型的纯右值。[...] null 成员指针值被转换\n 为 false;任何其他值都会转换为 true。[...]
\n
无需额外转换即可使用此转换来调用basic_ostream<charT,traits>& basic_ostream<charT,traits>::operator<<(bool n)。其他重载需要更长的转换序列,因此重载是最佳匹配。
as&A::a获取某个成员的地址,它不是空成员指针值。因此它将转换为true,打印为“1”(noboolalpha) 或“true”(boolalpha)。
最后,&(A::a)即使 a 在 A 中受到保护,该表达式在 B 的成员中也是有效的。根据上述规则,该表达式不会形成指向成员的指针,因此上面引用的特殊访问规则不适用。对于此类情况,11.4/1 继续:
\n\n\n所有其他访问都涉及(可能是隐式的)对象表达式\n (5.2.5)。在这种情况下,对象表达式的类应为 C\n 或从 C 派生的类。
\n
这里的对象印象是隐含的(*this),即A::a意味着与...相同(*this).A::a。显然的类型(*this)与访问发生的类(B)相同,因此允许访问。[注:int x = A(42).aB内不允许。]
因此,&(A::a)within 的B::show()含义与 as 相同&(this->a),并且是一个指向 int 的普通指针。
| 归档时间: | 
 | 
| 查看次数: | 1322 次 | 
| 最近记录: |