简体   繁体   English

以这种方式访问​​Base保护成员是否安全?

[英]Is it safe to access Base protected member this way?

I have two classes: 我有两节课:

class base
{
protected:
   int x;
};

class der: public base
{
   void Acc(base& b)
   {
      b.*(&der::x) = 5;
   }
};

Is it safe to access a base protected member this way (&der::x) ? 以这种方式(&der :: x)访问基本受保护的成员是否安全? I'm worried that it could point to a wrong variable. 我担心它可能指向一个错误的变量。


This is the way to pass by accessing protected member of a base class object. 这是通过访问基类对象的受保护成员来传递的方法。

在此输入图像描述

The above code: 上面的代码:

在此输入图像描述

For those who might find difficult to understand the below line 对于那些可能会发现下面很难理解的人

b.*(&der::x) = 5;

It can be written as: 它可以写成:

b.*(&(der::x)) = 5;

As scope resolution operator can be omitted as we have only one variable named x in base and derived class. 由于我们在base和派生类中只有一个名为x变量,因此可以省略作用域解析运算符。

b.*(&x) = 5;

Which is nothing but taking address of x and then again dereferencing it. 这只是取x地址,然后再取消引用它。 It can be written as: 它可以写成:

b.x = 5;

Which I hope you might be aware of. 我希望你可能会注意到这一点。 But your code won't compile if you use bx instead of 'b.*(&der::x) = 5;' 但是如果使用bx而不是'b。*(&der :: x)= 5,则代码将无法编译;' as 'x' is protected and this is used to bypass the compiler rule which prevents us from writing bx = 5; 因为'x'受到保护,这用于绕过编译器规则,阻止我们编写bx = 5;

是的,它是安全的 - 但它有点奇怪,并且会让读者感到困惑。

First of all don't make thing too complicated. 首先不要让事情变得太复杂。 When you compile this code it will never compile. 编译此代码时,它永远不会编译。 I will tell you why this code is complicated and why it will not compile. 我会告诉你为什么这段代码很复杂以及为什么它不能编译。

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.

class base { protected: int x; class base {protected:int x; } // End of base class } //基类结束

class der: public base { void Acc() { x = 5; class der:public base {void Acc(){x = 5; } }// End of der class. }} //类的结束。

 2> Why this code will not compile ?

*(&der::x) = 5; *(&der :: x)= 5;

This statement is correct and compile because it will put the value in x variable which is part of der class after the inheritance. 这个语句是正确的并且是编译的,因为它会将值放在x变量中,该变量是继承之后的类的一部分。 In other word we can say that statement. 换句话说,我们可以说这句话。

x = 5; x = 5;

*(&der::x) = 5; *(&der :: x)= 5;

are equivalent and doing same thing, but if you write a statement like 是等同的,并做同样的事情,但如果你写一个像这样的声明

b.(*(&der::x)) = 5; b。(*(&der :: x))= 5;

It will generate error because when you use dot operator(.) to call the member of class then just after the (.) you have to specify the member of the class. 它会产生错误,因为当你使用点运算符(。)来调用类的成员然后在(。)之后你必须指定类的成员。 So in above expression only x is the member of the class b except all will generate error. 所以在上面的表达式中,只有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.

What you are doing is an implicit cast, it is the same thing as writing static_cast<der&>(b).x = 5; 你正在做的是一个隐式演员,它与写static_cast<der&>(b).x = 5;

It is safe as long as you can be sure that the b argument is always of type der . 只要您可以确定b参数始终是der类型,它就是安全的。 What happens if you call it with some other type derived from base ? 如果您使用从base派生的其他类型调用它会发生什么? That type could use x for something else than der . 该类型可以使用x而不是der

class nuclear_submarine: public base {};

void dostuff(der d)
{
   nuclear_submarine ns;
   d.Acc(ns); // *poff*
}

This syntax is a work around to compile the code without an error by bypassing the access rules of protected members. 此语法是通过绕过protected成员的访问规则来编译代码而没有错误的解决方法。 Before we start keep this in mind: 在我们开始之前记住这一点:
" In class X methods, we can access all its members ( private , protected , public ), irrespective of the member belongs to this object or other object of class X . " class X方法中,我们可以访问其所有成员( privateprotectedpublic ),无论成员属于this对象还是属于class X其他对象。

Consider your function again: 再考虑一下你的功能:

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
}

Let's write the above code in little obfuscated way: 让我们以一种模糊的方式编写上面的代码:

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
}

And still add one more level: 并且仍然添加一个级别:

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
}

Now if you replace the 2nd statement by writing below statement: 现在如果你通过写下面的语句来替换第二个语句:

b.*(&der::x) = 5;

It compiles fine ! 编译好
In reality, it's equivalent to bx , but it bypasses the compiler rule which prevents us from writing bx = 5; 实际上,它等同于bx ,但它绕过了编译器规则,阻止我们编写bx = 5; .

But such kind of statement may often result in undefined behavior . 但是这种陈述可能经常导致不确定的行为 Because, imagine what happens if the b is passed as a reference of some_other_derived_class_of_base ! 因为,想象一下如果b作为some_other_derived_class_of_base的引用传递会发生什么! The best bet is to introduce access methods for x in class base 最好的办法是在class base引入x访问方法

void base::set_x (int v) { x = v; }

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

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