繁体   English   中英

为什么从 base 到派生的 static_cast 转换在 base 内部而不在外部有效

[英]Why static_cast conversion from base to derived works inside base but not outside

为什么从基类到派生的 static_case 转换在基类内部有效,但在基类之外不起作用

#include <iostream>
using std::cout;

class Base
{
public:
    template <typename T>
    int getValue() const { return static_cast<const T&>(*this).getValue(); }
};

class Derived: public Base
{
public:
    Derived(int v): value(v) { }
    int getValue() const { return value; }
    int value;
};

class Another
{
    int getValue() const { return 5; }
};

template <typename T>
void out(const Base & base) {
    cout << base.getValue<T>() << '\n';
}

int main() {
    Derived d(5);
    Base b;
    out<Derived>(d);    //understandable, d has derived part.
    out<Derived>(b);   //don't understand, b is only base.
    out<Another>(b);    //compile time error   
    //static_cast<Derived>(b);   //compile time error
}

我阅读这篇关于 CRTP 的文章并偶然发现了这段代码:

template <typename T>
class Base
{
public:
    void doSomething()
    {
        T& derived = static_cast<T&>(*this);
        use derived...
    }
};

class Derived : public Base<Derived>
{
    ...
};

而且我也不清楚转换在这里是如何工作的。

main() 中的最后一次转换在语法上是不正确的,并且不等同于模板中的代码,您不能将对象向上转换为对象(您可以向下转换,导致类型收缩)。 在上面的模板中,您可以转换引用。

Derived&可以绑定到Base&static_cast没有办法检查它。 CRTP 确保了this一点,因为在 Derived 类型的存储点上, *this导致引用可以安全地转换为Derived&引用对象。

参照Another不能被结合到参照Base ,当Base不是基类的Another 在这种情况下,使用static_cast转换指针或引用是非法的。

模板代码是合法的,在 CRTP 工作的情况下,因为模板代码在 Derived 是完整的类型的地方被设置,即在使用模板的地方。 模板本身不生成任何东西,也不编译,只检查正确性。

尽管如此,在 CRTP 中有些事情是不可能的,例如在基类内部使用派生类中的嵌套类型声明作为完整类型,原因很简单:它们不完整并且不受前向查找的影响,不像成员变量和职能。 如果需要这样的使用,则必须在 Base 之前定义第三种类型,包含必需的声明。

仅当此转换合法时才应使用static_cast转换。 在您的代码中,您正在创建Base类的对象,并尝试将其转换为Derived类。 幸运的是, Derived::getValue()实现不使用任何数据成员,并从文字返回一个值。 无论如何,这是未定义的行为。

在 CRTP 的情况下,不会创建Base类的实例:仅使用Derived实例。

更新。 尝试这个:

//static_cast<Derived>(b);   doesn't compile
static_cast<Derived&>(b);   shall compile

更新 2。因为Derived::getValue()使用数据成员(在您的代码的初始版本中未使用数据成员Derived::getValue()所以您会得到垃圾。

这是 C++ 规则的一部分。 static_cast可用于将基类表达式转换为派生类。 如果在运行时,该对象实际上不是派生类对象的基类子对象,则它是未定义的行为,无需诊断。

你的问题的第一句话是不正确的,这个演员可以写在代码的任何一点。

out<Another>()无法编译,因为AnotherBase没有继承关系。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM