Безопасно ли таким образом получить доступ к защищенному члену Base?

У меня два класса:

class base
{
protected:
   int x;
};

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

Безопасно ли таким образом получить доступ к базовому защищенному члену (& der :: x)? Меня беспокоит, что это может указывать на неправильную переменную.


Это способ передать доступ к защищенному члену объекта базового класса.

введите описание изображения здесь

Приведенный выше код:

введите описание изображения здесь


person user2663010    schedule 08.08.2013    source источник
comment
вы только что унаследовали его, зачем вам так обращаться к нему   -  person aaronman    schedule 08.08.2013
comment
также это даже не компилируется   -  person aaronman    schedule 08.08.2013
comment
Я полагаю, вам нравится код, который легко поддерживать. Или у вас проблемы с безопасностью работы?   -  person Ed Heal    schedule 08.08.2013
comment
TC ++ PL утверждает, что производный класс может получить доступ к защищенным членам базового класса только для объектов его собственного типа. Это предотвращает незаметные ошибки, которые в противном случае могли бы возникнуть, когда один производный класс повреждает данные, принадлежащие другим производным классам.   -  person dalle    schedule 08.08.2013
comment
Собственно, я использую XCode, и приведенный выше код скомпилирован! Тем не менее, спасибо всем вам, ребята.   -  person user2663010    schedule 08.08.2013


Ответы (5)


Для тех, кому сложно понять нижеследующую строку

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;

person Saksham    schedule 08.08.2013
comment
Он бы не компилировался без сложного оператора. - person dalle; 08.08.2013
comment
@dalle У меня он компилируется и работает нормально. не могли бы вы немного уточнить - person Saksham; 08.08.2013
comment
@dalle Я использую VS2010, и он отлично работает. - person Saksham; 08.08.2013
comment
Я использую VS2010 и получаю сообщение об ошибке C2248: 'base :: x': не удается получить доступ к защищенному члену, объявленному в классе 'base' - person dalle; 08.08.2013

Да, это безопасно, но это более чем немного странно и будет сбивать с толку читателей.

person Casey    schedule 08.08.2013

Прежде всего, не усложняйте задачу. Когда вы скомпилируете этот код, он никогда не будет компилироваться. Я расскажу, почему этот код сложен и почему он не компилируется.

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; } // Конец базового класса

class der: public base {void Acc () {x = 5; }} // Конец класса der.

 2> Why this code will not compile ?

* (& der :: x) = 5;

Этот оператор является правильным и компилируется, потому что он помещает значение в переменную x, которая является частью класса der после наследования. Другими словами, мы можем сказать это утверждение.

x = 5;

* (& der :: x) = 5;

эквивалентны и делают то же самое, но если вы напишете такой оператор, как

б. (* (& 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.
person Antrikssh    schedule 08.08.2013

То, что вы делаете, - это неявное приведение, это то же самое, что писать static_cast<der&>(b).x = 5;

Это безопасно, если вы можете быть уверены, что аргумент b всегда имеет тип der. Что произойдет, если вы вызовете его с другим типом, производным от base? Этот тип мог использовать x для чего-то еще, кроме der.

class nuclear_submarine: public base {};

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

Этот синтаксис представляет собой обходной путь для компиляции кода без ошибок путем обхода правил доступа protected членов. Прежде чем мы начнем, запомните следующее:
"В class X методах мы можем получить доступ ко всем его членам (private, protected, public), независимо от того, принадлежит ли член объекту this или другому объекту _7 _. "

Снова рассмотрим свою функцию:

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 в class base

void base::set_x (int v) { x = v; }
person iammilind    schedule 08.08.2013