我有两节课:
class base
{
protected:
int x;
};
class der: public base
{
void Acc(base& b)
{
b.*(&der::x) = 5;
}
};
以这种方式访问基本受保护成员是否安全 (&der::x) ?我担心它可能指向错误的变量。
这是通过访问基类对象的受保护成员的方式。
上面的代码:
对于那些可能难以理解以下行的人
b.*(&der::x) = 5;
它可以写成:
b.*(&(der::x)) = 5;
由于范围解析运算符可以省略,因为我们只有一个x
在基类和派生类中命名的变量。
b.*(&x) = 5;
这只不过是获取地址x
然后再次取消引用它。它可以写成:
b.x = 5;
我希望你能意识到这一点。但是,如果您使用b.x
而不是 'b.*(&der::x) = 5;',您的代码将无法编译 因为“x”是受保护的,这用于绕过阻止我们编写的编译器规则b.x = 5;
是的,它是安全的——但它有点奇怪,而且会让读者感到困惑。
首先不要把事情搞得太复杂。当你编译这段代码时,它永远不会编译。我会告诉你为什么这段代码很复杂,为什么它不能编译。
1> Why this code is complicated ?
According to the basic of c++ we can easily access the protected member of base
class in drive class. So you can write you code like this.
类基{受保护:int x;} // 基类结束
类 der:公共基础 { void Acc() { x = 5; } }// der 类结束。
2> Why this code will not compile ?
*(&der::x) = 5;
该语句是正确且可编译的,因为它将值放入继承后属于 der 类的 x 变量中。换句话说,我们可以说这种说法。
x = 5;
*(&der::x) = 5;
是等价的并且做同样的事情,但是如果你写一个像
b.(*(&der::x)) = 5;
它将产生错误,因为当您使用点运算符(。)来调用类的成员时,就在 (.) 之后,您必须指定类的成员。所以在上面的表达式中只有 x 是类 b 的成员,除了所有都会产生错误。
Conclusion, if code will not compile then how we can say it is safe or not. Code is
safe or not is depend on the resource utilization, which it will during runtime.
您正在做的是隐式转换,这与写作相同static_cast<der&>(b).x = 5;
只要您可以确定b
参数始终是 type ,它就是安全的der
。如果您使用派生自 的其他类型调用它会发生什么base
?该类型可以x
用于除der
.
class nuclear_submarine: public base {};
void dostuff(der d)
{
nuclear_submarine ns;
d.Acc(ns); // *poff*
}
这种语法是绕过protected
成员的访问规则来编译代码而不会出错的一种解决方法。在我们开始之前记住这一点:
“在class X
方法中,我们可以访问它的所有成员(private
, protected
, public
),而不管该成员属于this
对象还是其他对象class X
。 ”
再次考虑您的功能:
void Acc(base& b)
{
x = 5; // ok, because `x` is a protected member to `this` object
b.x = 5; // error, because `b` isn't part of `this` object
}
让我们以稍微混淆的方式编写上面的代码:
void Acc(base& b)
{
this->(base::x) = 5; // ok, because `x` is a protected member to `this` object
b.(base::x) = 5; // error, because `b` isn't part of `this` object
}
并且还增加了一层:
void Acc(base& b)
{
this->*(&der::x) = 5; // ok, because `x` is a protected member to `this` object
b.*(&base::x) = 5; // error, because `b` isn't part of `this` object
}
现在,如果您通过编写以下语句替换第二条语句:
b.*(&der::x) = 5;
它编译得很好!
实际上,它等价于b.x
,但它绕过了阻止我们编写b.x = 5;
.
但这样的陈述往往会导致未定义的行为。因为,想象一下如果b
作为参考传递会发生什么some_other_derived_class_of_base
!最好的办法是为x
in引入访问方法class base
void base::set_x (int v) { x = v; }