类型强制转换的c++赋值
C++ assignment on type cast
我今天偶然发现了类似的东西,随后尝试了一些东西,并注意到以下内容在g++中似乎是合法的:
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) { val_ = val; return *this; }
int get() { return val_; }
};
struct B : public A {
A getA() { return (((A)*this) = 20); } // legal?
};
int main() {
A a = 10;
B b;
A c = b.getA();
}
因此,B::getB
在将值20
赋值给自身(通过重载的A::operator=
)之后返回类型A
。
经过几次测试后,它似乎返回正确的值(c.get
将返回20
,正如人们所期望的那样)。
所以我想知道,这是未定义行为吗?如果是这样,究竟是什么原因呢?如果不是,这种代码的优点是什么?
经过仔细检查,在@Kerrek SB和@Aaron McDaid的帮助下,如下:
return (((A)*this) = 20);
…类似于
的简写(但模糊)语法:A a(*this);
return a.operator=(20);
…或者更好:
return A(*this) = 20;
…
这里发生了许多完全不同的事情。代码是有效的,但是你在你的问题中做了一个错误的假设。你说
"B::getA返回[…]],然后将值20赋给本身"
(我强调)这是不正确的。getA 不修改对象。为了验证这一点,您可以简单地将const
放在方法签名中。我会详细解释的。
A getA() const {
cout << this << " in getA() now" << endl;
return (((A)*this) = 20);
}
这是怎么回事?看看我的示例代码(我已经复制了我的成绩单到这个答案的末尾):
A a = 10;
用构造函数声明一个A。很乾脆。下一行:
B b; b.val_ = 15;
B没有任何构造函数,所以我必须直接写入它的val_成员(继承自A)。
在考虑下一行A c = b.getA();
之前,我们必须非常仔细地考虑更简单的表达式:
b.getA();
这不会修改b
,尽管表面上看起来是这样。
最后,我的示例代码打印出b.val_
,您可以看到它仍然等于15。它没有变成20。c.val_
当然变成了20。
看看getA
内部,你会看到(((A)*this) = 20)
。我们来分析一下:
this // a pointer to the the variable 'b' in main(). It's of type B*
*this // a reference to 'b'. Of type B&
(A)*this // this copies into a new object of type A.
值得在这里暂停一下。如果这是(A&)*this
,甚至*((A*)this)
,那么这将是一条更简单的线。但它是(A)*this
,因此这创建了一个类型为a的新对象,并将b的相关切片复制到它中。
(额外:您可能会问它如何复制切片。我们有一个B&
引用,我们希望创建一个新的A
。默认情况下,编译器创建一个复制构造函数A :: A (const A&)
。编译器可以使用这一点,因为引用B&
可以自然地强制转换为const A&
。
特别是this != &((A)*this)
。这可能会让你大吃一惊。(额外:另一方面this == &((A&)*this)
通常(取决于是否有virtual
方法))
现在我们有了这个新对象,我们可以看
((A)*this) = 20
将数字放入新值中。不影响this->val_
.
将getA
更改为返回A&
是错误的。首先,operator=
的返回值是const A&
,因此您不能将其作为A&
返回。但是,即使您将const A&
作为返回类型,这也将是对在getA内部创建的临时局部变量的引用。返回这样的东西是没有定义的。
最后,我们可以看到c
将获取getA
A c = b.getA();
这就是为什么当前的代码,其中getA按值返回副本,是安全和定义良好的。 ==完整程序==#include <iostream>
using namespace std;
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) {
cout << this << " in operator= now" << endl; // prove the operator= happens on a different object (the copy)
val_ = val;
return *this;
}
int get() { return val_; }
};
struct B : public A {
A getA() const {
cout << this << " in getA() now" << endl; // the address of b
return (((A)*this) = 20);
// The preceding line does four things:
// 1. Take the current object, *this
// 2. Copy a slice of it into a new temporary object of type A
// 3. Assign 20 to this temporary copy
// 4. Return this by value
} // legal? Yes
};
int main() {
A a = 10;
B b; b.val_ = 15;
A c = b.getA();
cout << b.get() << endl; // expect 15
cout << c.get() << endl; // expect 20
B* b2 = &b;
A a2 = *b2;
cout << b2->get() << endl; // expect 15
cout << a2.get() << endl; // expect 15
}
- 为"adjacent"变量赋值时出现问题
- C++中的赋值发生,尽管右侧出现异常
- 用C++中的sscanf赋值
- 为std::string的某个索引赋值
- 重载Singly Linked List中的赋值运算符
- 为什么我必须在C++中添加一个赋值符号来声明一个数组
- gtest_使用setargpointee在函数中赋值
- 非常量变量只读位置的赋值
- 使用赋值运算符重载从类中返回jobject
- C++数据文件、数组和计算赋值
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 全局作用域中函数指针的赋值
- 错误:在为指针赋值时,void值没有被忽略
- 标准库类型的赋值运算符的引用限定符
- 关于 c++ 函数中指针赋值的简单问题
- 复制构造函数、赋值运算符C++
- 标准::变体的赋值运算符
- cin >> int 给定一个字符串将 int 赋值为 0
- if 子句中的赋值不起作用
- 复制包含C++所有元素的对象!(构造函数和赋值,最佳实践?