gpt4 book ai didi

c++ - 您可以将 "this"静态转换为基类构造函数中的派生类,然后稍后使用结果吗?

转载 作者:行者123 更新时间:2023-12-05 03:20:22 25 4
gpt4 key购买 nike

我们在工作中的代码库中遇到了这种情况,我们就这是否是有效的 C++ 展开了激烈的争论。这是我能想出的最简单的代码示例:

template <class T>
class A {
public:
A() { subclass = static_cast<T*>(this); }
virtual void Foo() = 0;
protected:
T* subclass;
};

class C : public A<C> {
public:
C(int i) : i(i) { }
virtual void Foo() { subclass->Bar(); }
void Bar() { std::cout << "i is " << i << std::endl; }
private:
int i;
};

int main() {
C c(5);
c.Foo();
return 0;
}

这段代码在实践中 100% 有效(只要模板参数类型与子类类型匹配),但如果我们通过运行时分析器运行它,它会告诉我们 static_cast无效,因为我们将 this 转换为 C*C 构造函数尚未运行。果然,如果我们将 static_cast 更改为 dynamic_cast,它返回 nullptr 并且此程序将在访问 i< 时失败并崩溃Bar() 中。

我的直觉是,应该总是可以用 dynamic_cast 替换 static_cast 而不会破坏您的代码,这表明原始代码实际上取决于特定于编译器的 undefined行为。然而,on cppreference它说:

If the object expression refers or points to is actually a base class subobject of an object of type D, the result refers to the enclosing object of type D.

问题是,在D类型的对象构造完成之前,它是D类型对象的基类子对象吗?或者这是未定义的行为?我的 C++ 规则律师水平不足以解决这个问题。

最佳答案

在我看来,根据标准的当前措辞,这是明确定义的:C对象在 static_cast 时存在,尽管它正在 build 中并且其生命周期尚未开始。这似乎使 static_cast根据 [expr.static.cast]/11 定义良好,部分内容如下:

... If the prvalue of type “pointer to cv1 B” points to a B that is actually a base class subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.

它并没有说 D对象的生命周期必须已经开始。

我们可能还想查看有关执行从派生到基的隐式转换何时合法的明确规则,[class.cdtor]/3 :

To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.

根据这个规则,一旦编译器开始构造基类A<C> , 从 C* 隐式转换是明确定义的至 A<C>* .在那之前,它会导致 UB。其原因基本上与虚拟基类有关:如果 A<C> 的路径由 C 继承包含任何虚拟继承,转换可能依赖于链中构造函数之一设置的数据。对于从base到derived的转换,如果链上确实存在虚拟继承,static_cast不会编译,所以我们真的不需要问自己这个问题,但是这些数据是否足以让我们走另一条路?

对于 static_cast,我真的在标准文本中看不到任何内容,也看不到任何理由在您的示例中没有明确定义,在 static_cast 的任何其他情况下也没有当允许反向隐式转换(或 static_cast )时从 base 到 derived (虚拟继承的情况除外,正​​如我之前所说,无论如何都会导致编译错误)。

(如果更早执行此操作是否定义明确?在大多数情况下这是不可能的;在从 static_cast 转换之前,您怎么可能尝试将 B*D* 转换为 D*B* 是允许的,而没有通过执行后者精确地获得 B* 指针?如果答案是你从 D*B* 通过中间基类 C1 其构造函数已启动,但是有另一个中间基类 C2 共享相同的 B 基类子对象并且它的构造尚未开始,那么 B 是一个虚拟基类,同样,这意味着编译器将阻止您尝试从 static_castB* 回到 D* 。所以我认为这里没有任何问题需要解决。)

关于c++ - 您可以将 "this"静态转换为基类构造函数中的派生类,然后稍后使用结果吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73172193/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com