为什么 static_cast 从 base 到 derived 的转换在 base 内部有效,但在外部无效
Why static_cast conversion from base to derived works inside base but not outside
为什么 static_case 从基础 class 到派生的转换在基础 class 内部有效,但在基础 class[= 之外不起作用21=]
#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
}
我阅读了 this 有关 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
指向派生类型的存储,*this
导致可以安全地转换为 Derived&
引用对象的引用。
当 Base
不是 Another
的基础 class 时,对 Another
的引用不能绑定到对 Base
的引用。在那种情况下,使用 static_cast
强制转换指针或引用是非法的。
如果 CRTP 有效,模板代码是合法的,因为模板代码是在 Derived 类型足够完整的地方实例化的,即使用模板的地方。模板本身不生成任何东西,也不编译,只检查正确性。
不过,在 CRTP 中有些事情是不可能的,例如在 Base class 内部使用 Derived class 的嵌套类型声明作为完整类型,原因很简单:与成员变量和函数不同,它们不完整并且不受正向查找的影响。如果需要这样使用,则必须在 Base 之前定义第三种类型,并包含所需的声明。
static_cast
转换仅在该转换合法时使用。在您的代码中,您正在创建 class Base
的对象,并且您正试图将其转换为 class Derived
。幸运的是,Derived::getValue()
的实现不使用任何数据成员,而 returns 是来自文字的值。无论如何,这是未定义的行为。
如果是 CRTP,则不会创建 Base
class 的实例:仅使用 Derived
的实例。
更新。试试这个:
//static_cast<Derived>(b); doesn't compile
static_cast<Derived&>(b); shall compile
Upd 2. 你变得垃圾是因为 Derived::getValue()
使用了一个数据成员(在你的初始版本的代码中没有使用数据成员)。
这是C++规则的一部分。 static_cast
可用于将基本 class 表达式转换为派生 class。如果在运行时,对象实际上不是派生 class 对象的基 class 子对象,那么它是未定义的行为,不需要诊断。
你的问题第一句不对,这个cast可以写在代码的任何一点。
out<Another>()
编译失败,因为 Another
与 Base
.
没有继承关系
为什么 static_case 从基础 class 到派生的转换在基础 class 内部有效,但在基础 class[= 之外不起作用21=]
#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
}
我阅读了 this 有关 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
指向派生类型的存储,*this
导致可以安全地转换为 Derived&
引用对象的引用。
当 Base
不是 Another
的基础 class 时,对 Another
的引用不能绑定到对 Base
的引用。在那种情况下,使用 static_cast
强制转换指针或引用是非法的。
如果 CRTP 有效,模板代码是合法的,因为模板代码是在 Derived 类型足够完整的地方实例化的,即使用模板的地方。模板本身不生成任何东西,也不编译,只检查正确性。
不过,在 CRTP 中有些事情是不可能的,例如在 Base class 内部使用 Derived class 的嵌套类型声明作为完整类型,原因很简单:与成员变量和函数不同,它们不完整并且不受正向查找的影响。如果需要这样使用,则必须在 Base 之前定义第三种类型,并包含所需的声明。
static_cast
转换仅在该转换合法时使用。在您的代码中,您正在创建 class Base
的对象,并且您正试图将其转换为 class Derived
。幸运的是,Derived::getValue()
的实现不使用任何数据成员,而 returns 是来自文字的值。无论如何,这是未定义的行为。
如果是 CRTP,则不会创建 Base
class 的实例:仅使用 Derived
的实例。
更新。试试这个:
//static_cast<Derived>(b); doesn't compile
static_cast<Derived&>(b); shall compile
Upd 2. 你变得垃圾是因为 Derived::getValue()
使用了一个数据成员(在你的初始版本的代码中没有使用数据成员)。
这是C++规则的一部分。 static_cast
可用于将基本 class 表达式转换为派生 class。如果在运行时,对象实际上不是派生 class 对象的基 class 子对象,那么它是未定义的行为,不需要诊断。
你的问题第一句不对,这个cast可以写在代码的任何一点。
out<Another>()
编译失败,因为 Another
与 Base
.