C++ 如何在不调用成员函数的情况下修改对象?
在3.10/10中,标准规定: 为了修改对象,对象的左值是必需的,但类类型的右值在某些情况下也可用于修改其引用。[示例:为对象(9.3)调用的成员函数可以修改该对象。] 因此,右值是不可修改的,除非在某些情况下。我们被告知调用成员函数是例外情况之一。这就产生了这样的想法:除了调用成员函数之外,还有其他方法可以修改对象。我想不出一个办法C++ 如何在不调用成员函数的情况下修改对象?,c++,C++,在3.10/10中,标准规定: 为了修改对象,对象的左值是必需的,但类类型的右值在某些情况下也可用于修改其引用。[示例:为对象(9.3)调用的成员函数可以修改该对象。] 因此,右值是不可修改的,除非在某些情况下。我们被告知调用成员函数是例外情况之一。这就产生了这样的想法:除了调用成员函数之外,还有其他方法可以修改对象。我想不出一个办法 如何在不调用成员函数的情况下修改对象?我可以想出一种方法: 如果您的类公开了公共成员变量,则可以直接分配给这些成员变量。例如: class A { pub
如何在不调用成员函数的情况下修改对象?我可以想出一种方法: 如果您的类公开了公共成员变量,则可以直接分配给这些成员变量。例如:
class A
{
public:
int _my_var;
...
};
int main(int argc, char** argv)
{
A *a = new C();
a->_my_var = 10;
}
不过,这不是一种好的编程风格——将成员变量公开为公共变量并不是我所提倡或建议的
此外,如果您可以做一些非常奇怪的事情,例如直接在内存中写入一些地址,从指向类对象的指针的偏移量-但是为什么要这样做呢?这是: 我对此有点惊讶,因为IIRC
op=
的LHS必须是一个左值,但下面暗示:
编辑:从4.6开始,GCC确实警告了T().x=3
:错误:使用临时值作为左值
除了通过数据成员访问或成员函数调用之外,我想不出任何其他方法来修改类对象。所以,我要说你不能
如何在不调用成员函数的情况下修改对象
当然,通过将值指定给对象的一个可见数据成员
如何在不调用成员函数的情况下修改[由右值表达式指定的]对象
我只知道一种方法,即将对象绑定到对const
的引用,然后丢弃const
-ness
例如
模板
Type&tempRef(Type const&o){return const_cast(o);}
结构S{int x;};
int main()
{tempRef(S()).x=3;}
这是因为临时对象本身不是const
,除非它是const
类型,因此上面的示例不会抛弃原始的const
-ness(即UB)
编辑,补充道:“这个问题的答案显示了另一种(非常规)方式,即临时结构将指向对象的引用或指针存储在某个可访问的位置
干杯,修改临时值,而不是通过左值修改该临时值:
#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) );
}
#包括
类标准布局{
标准_布局();
智力材料;
};
标准布局*全球;
标准布局::标准布局()
{global=this;}
无效的
修改(int)
{
std::memset(全局,0,sizeof*global);
}
int
main()
{
修改((标准_布局{},0));
}
我认为假设类类型的右值是不可修改的是不正确的。我现在理解为“对于非类类型,需要对象的左值才能修改该对象”。执行隐式强制转换有点像调用成员函数——修改右值引用似乎也可以
在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 */ }
成员函数可以直接更改成员,但也可以委派该职责:
struct Foo {
int x;
void Bar() { scanf("%d", &x); }
};
本标准目前的措词有一个优点,即不需要争论这是否是Bar
更改对象的情况。如果我们同意scanf
更改对象,那么这只是另一个例子。写入对象的字段是否会被视为修改对象?(这是出于)非常困难。首先,你不能使用函数,因为你不能通过调用获得可变的ref。@Martinho:你的意思是“这会让你产生这样的想法,即你不能在不调用成员函数的情况下修改对象”@Sasha,是的,那当然是修改。(我怎么会忘记呢?)如果我可以“如果你能做一些非常奇怪的事情,比如直接在内存中写一些地址,一个指向类对象指针的偏移量”,我会把它作为一个注释,怎么说?临时变量在你有机会之前就不存在了,而且它没有内存地址。这个答案与右值有什么关系?g++在T()行上说error:使用临时变量作为左值[-fppermissive]
。x=3
@Fred:您使用的是什么标志g++-Wall-Wextra-pedantic
在第一个示例中没有给出任何输出。另外,还可以通过例如std::memset
修改适当类型的对象,但由于这需要一个指针,因此它也不能应用于右值。@Alf:int
的著名复制赋值运算符@DeadMG:默认情况下不是。您需要--std=c++0x来实现这一点,但这是标准在3.10/10中所说的。你不是在用左值吗?或者该对象最初被视为右值是否相关?啊@调用memset时出现的Tomalakglobal
是一个左值,但不是被修改对象的左值(即*global
),如段落中所示。@Luc:Hmm确定。虽然想必,在某一点上memset
正在使用*global
@Tomalak,但我相信使用char指针的memset
将符合(而且,很明显)和*(char*)这不是*这@Luc的左值:没有“使用”的左值到右值转换?“这是因为临时对象本身不是常量,除非它是常量类型“,但这只能保证在C++0x中是如此-应该提到。嗯,您正在调用一个成员函数。我们不需要争论这是否是Bar
改变对象的情况,因为它改变了对象,而不是因为标准中的任何措辞。你是
#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) );
}
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 */ }
struct Foo {
int x;
void Bar() { scanf("%d", &x); }
};