Как вы можете изменить объект без вызова функций-членов?
В 3.10/10 стандарт гласит:
Lvalue для объекта необходимо для того, чтобы изменить объект, за исключением того, что rvalue типа class может также использоваться для изменения его референта при определенных обстоятельствах. [Пример: функция-член, вызываемая для объекта (9.3), может модифицировать объект. ]
Таким образом, значения не могут быть изменены, за исключением определенных обстоятельств. Нам говорят, что вызов функции-члена является одним из таких исключений. Это дает представление о том, что существуют способы изменения объектов, отличные от вызова функции-члена. Я не могу придумать способ.
Как можно изменить объект, не вызывая функцию-член?
7 ответов
Как можно изменить объект [который указан выражением rvalue] без вызова функции-члена?
Я знаю только один способ сделать это, а именно связать объект со ссылкой на const
, а затем выбросить const
-ness.
Например
template< class Type >
Type& tempRef( Type const& o ) { return const_cast< Type& >( o ); }
struct S { int x; };
int main()
{ tempRef( S() ).x = 3; }
Это потому, что временный объект не const
само по себе, если это не const
тип, так что пример выше не отбрасывает оригинал const
-несс (что было бы UB).
РЕДАКТИРОВАТЬ, добавил: Ответ Люка Дантона показал другой (не общий) способ, а именно, где конструкция временного хранит некоторую ссылку или указатель на объект в некотором доступном месте.
Ура & hth.,
struct T {
int x;
};
int main() {
T().x = 3;
}
Я немного удивлен, что это работает, потому что IIRC LHS op=
должно быть lvalue, но из следующего следует, что даже T().x
это значение:
struct T {
int x;
};
void f(int& x) {
x = 3;
}
int main() {
f(T().x);
}
Изменить: Начиная с 4.6, GCC предупреждает о T().x = 3
: error: using temporary as lvalue
,
Я не могу придумать никакого другого способа изменить объект класса, кроме как через доступ к элементам данных или вызовы функций-членов. Итак, я собираюсь сказать... вы не можете.
Изменение временного а не через lvalue к этому временному:
#include <cstring>
class standard_layout {
standard_layout();
int stuff;
};
standard_layout* global;
standard_layout::standard_layout()
{ global = this; }
void
modify(int)
{
std::memset(global, 0, sizeof *global);
}
int
main()
{
modify( (standard_layout {}, 0) );
}
Я не думаю, что правильно предполагать, что значения классов не изменяются. Теперь я понимаю этот абзац как "для типов, не относящихся к классу, для изменения этого объекта необходимо lvalue для объекта".
Выполнение неявного приведения типа похоже на вызов функции-члена - похоже, также работает изменение ссылок на rvalue.
Проверено следующее в vC++10 и g++ 4.4.
struct b { int i; b(int x) : i(x) {} };
struct a { int i; a() : i(0) { } operator b() { return i++ /* this works */, b(i); } };
a f(a&& x) { return x.i++ /* this works */, x; }
int main() { b b = f(a()); /* implicit operator b() cast; b.i will equal 2 */ }
Я могу придумать один способ:
Если ваш класс предоставляет открытые переменные-члены, вы можете назначить эти переменные-члены напрямую. Например:
class A
{
public:
int _my_var;
...
};
int main(int argc, char** argv)
{
A *a = new C();
a->_my_var = 10;
}
Хотя это не очень хороший стиль программирования - выставлять переменную-член как public - это не то, что я бы отстаивал или даже предлагал.
Кроме того, если вы можете сделать что-то действительно странное, например, напрямую записать какой-либо адрес в память, смещение от указателя на объект класса - но зачем вам это делать?
Как можно изменить объект, не вызывая функцию-член?
Разумеется, присваивая значение одному из видимых элементов данных объекта.
Функция-член может изменять члена напрямую, но она также может делегировать эту ответственность:
struct Foo {
int x;
void Bar() { scanf("%d", &x); }
};
Существующая редакция стандарта имеет то преимущество, что не нужно спорить, является ли это Bar
изменение объекта. Если бы мы согласились с этим scanf
меняет объект, то это просто еще один пример.