C++ 如何在不调用成员函数的情况下修改对象?

C++ 如何在不调用成员函数的情况下修改对象?,c++,C++,在3.10/10中,标准规定: 为了修改对象,对象的左值是必需的,但类类型的右值在某些情况下也可用于修改其引用。[示例:为对象(9.3)调用的成员函数可以修改该对象。] 因此,右值是不可修改的,除非在某些情况下。我们被告知调用成员函数是例外情况之一。这就产生了这样的想法:除了调用成员函数之外,还有其他方法可以修改对象。我想不出一个办法 如何在不调用成员函数的情况下修改对象?我可以想出一种方法: 如果您的类公开了公共成员变量,则可以直接分配给这些成员变量。例如: class A { pub

在3.10/10中,标准规定:

为了修改对象,对象的左值是必需的,但类类型的右值在某些情况下也可用于修改其引用。[示例:为对象(9.3)调用的成员函数可以修改该对象。]

因此,右值是不可修改的,除非在某些情况下。我们被告知调用成员函数是例外情况之一。这就产生了这样的想法:除了调用成员函数之外,还有其他方法可以修改对象。我想不出一个办法


如何在不调用成员函数的情况下修改对象?

我可以想出一种方法:

如果您的类公开了公共成员变量,则可以直接分配给这些成员变量。例如:

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时出现的Tomalak
global
是一个左值,但不是被修改对象的左值(即
*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); }
};