this->
是安全的。特别是从构造函数和析构函数内部。
而且,在使用公共继承时。使用向上和向下转换此调用的结果是否安全?
例如:
class foo
{
foo():
a(),
b(this->a)//case 1
{
this-> a = 5; //case 2
}
int a;
int b;
};
class bar: public baz
{
bar():
baz(this)//case 3 - assuming baz has a valid constructor
{
}
}
最后是最不可能的一个
foo()
{
if(static_cast<bar*>(this));//case 4
}
上述哪些案件合法?
注意:我知道上面的很多做法都是不可取的。
答案 0 :(得分:34)
在任何非静态成员函数中,this
指向调用该函数的对象。只要这是一个有效的对象,它就是安全的。
在构造函数或析构函数的主体内,有一个当前正在构造的类的有效对象。但是,如果这是某个派生类的基础子对象,则此时只有基础子对象有效;因此,向下转换并尝试访问派生类的成员通常是不安全的。出于同样的原因,你需要小心地在这里调用虚函数,因为它们是根据正在创建或销毁的类调度的,而不是最终的覆盖。
在构造函数的初始化列表中,您只需要小心访问已初始化的成员;也就是说,成员在当前正在初始化之前声明。
向上扩展到基类总是安全的,因为基本子对象总是先被初始化。
对于您刚刚添加到问题的具体示例:
a
已在此时初始化。使用a
的值初始化b
将是未定义的,因为在b
之后初始化a
。foo
构造函数。如果有,那么它将取决于构造函数对它做了什么 - 无论它是否在初始化之前尝试访问成员。)
,则情况4将是格式良好的,但如果您尝试使用指针访问该对象则会很危险。 this
尚未指向有效的bar
对象(仅foo
部分已初始化),因此访问bar
的成员可能会给出未定义的行为。只需检查指针是否为空即可,并且总是会给true
(无论你是否应用无意义的强制转换)。答案 1 :(得分:19)
在C ++ super-faq上有一个很好的条目:
https://isocpp.org/wiki/faq/ctors#using-this-in-ctors
有些人认为你不应该在构造函数中使用this指针 因为物体尚未完全形成。但是你可以使用它 在构造函数中(在{body}中,甚至在初始化列表中) 如果你小心的话。
以下是始终有效的东西:构造函数的{body}(或者 从构造函数调用的函数)可以可靠地访问数据 在基类中声明的成员和/或在中声明的数据成员 构造函数自己的类。这是因为所有这些数据成员 保证在时间之前完全建造 构造函数的{body}开始执行。
这是永远不会有用的东西:构造函数的{body}(或者 从构造函数调用的函数)无法归结为派生函数 class通过调用在。中重写的虚拟成员函数 派生类。如果你的目标是获得被覆盖的功能 派生类,你不会得到你想要的。请注意,你不会 获取派生类中的覆盖,与您调用的方式无关 虚拟成员函数:显式使用this指针(例如, this-&gt; method()),隐式使用this指针(例如,method()), 甚至调用一些调用虚拟成员的其他函数 对你的这个对象起作用。底线是这样的:即使是 调用者正在构造一个派生类的对象 基类的构造函数,您的对象尚未派生 类。你被警告了。
以下是有时可行的方法:如果您传递任何数据 您必须在此对象中的成员到另一个数据成员的初始化程序 确保已初始化其他数据成员。该 好消息是你可以确定其他数据成员是否有 (或尚未)使用一些简单的语言进行初始化 与您正在使用的特定编译器无关的规则。 坏消息是你必须知道那些语言规则(例如,基础 首先初始化class子对象(如果有的话,查找顺序) 多个和/或虚拟继承!),然后定义数据成员 该类按它们出现在的顺序初始化 班级宣言)。如果您不了解这些规则,那么请不要通过任何规则 来自此对象的数据成员(无论您是否 显式地使用this关键字)到任何其他数据成员 初始化!如果您确实了解规则,请小心。