静态转换允许对象指针的转换,但不能转换整数

Static cast allows conversion of object pointers but not integers

为什么静态转换允许在指向派生对象或基类对象的指针之间进行向上转换或向下转换,如下所示,但在 char* 和 int* 之间转换或反之亦然 int* 到 char* 的情况下,有一个编译错误?

我认为在指向对象的不同指针之间进行转换同样糟糕。

// compiles fine
class Base {};
class Derived: public Base {};
Base * a = new Base;
Derived * bc = static_cast<Derived*>(a);

// Gives an invalid static cast error during compilation
char charVar = 8;
char* charPtr = &charVar;
int* intPtr = static_cast<int*>(charPtr);

Why does static cast allow an upcast ...

没有理由阻止upcast。事实上,派生指针甚至可以隐式转换为基指针——不需要强制转换(除非在复杂的情况下有多个相同类型的基)。派生 class 对象始终包含基础 class 子对象。

向上转型特别有用,因为它允许 运行通过使用虚函数实现时间多态性。

or downcast between pointers to objects derived or base as below

基指针可能指向派生对象的基子对象,作为向上转型的结果。例如这里:

Derived d;
Base *b = &d;

在某些情况下,您可能想要访问 知道指向的派生对象的成员。静态转换使这成为可能,而无需 运行 时间类型信息。

编译器通常不可能找出(在编译时)指向对象的具体类型(即指针是否指向子对象,如果是,对象的类型是什么)容器对象)。程序员有责任确保满足演员表的要求。如果程序员无法证明正确性,那么编写静态转换就是一个错误。

那是因为你想做的是重新解释 - 为此有 reinterpret_cast<> operator. static_cast<> for pointers is only used for down-casting:

  1. If new_type is a pointer or reference to some class D and the type of expression is a pointer or reference to its non-virtual base B, static_cast performs a downcast. This downcast is ill-formed if B is ambiguous, inaccessible, or virtual base (or a base of a virtual base) of D. Such static_cast makes no runtime checks to ensure that the object's runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism. Safe downcast may be done with dynamic_cast.

参见:

When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?

详细讨论何时使用每个转换运算符。

C++ 非常注重性能。因此,只要有一些您可以获得性能的用例,C++ 就会允许您这样做。考虑 std::vector:当然,可以通过函数 at 访问安全元素,它会为您进行范围检查。但是如果你知道你的索引 范围内(例如在 for 循环中),这些范围检查只是自重。因此,您还得到了(不太安全)operator[],它只是忽略了这些检查。

类似地,如果您有一个 Base 类型的指针,它实际上可能指向一个 Derived 类型的对象。如果有疑问,你会 dynamic_castBase*Derived*。但这会带来一些开销。但是如果你 100% 确定(通过任何方式......) sub class 实际上是什么,你会想要这个开销吗?由于存在从 Derived*Base* 的自然(甚至隐含!)方式,我们希望有一些低成本的方式返回。

另一方面,在完全不相关的类型(例如 charint 或两个不相关的 class 的指针之间没有这种自然转换,因此没有这样的低成本回归(与 dynamic_cast 相比,后者当然也不可用)。在两者之间转换的唯一方法是 reinterpret_cast.

实际上,reinterpret_cast 也没有任何成本,它只是将指针解释为不同的类型——有所有风险! reinterpret_cast 甚至可能会失败,如果需要 static_cast(防止问题 "why not just always use ..." 的权利):

class A { int a; };
class B { };
class C : public A, public B { };

B* b = new C();
C* c = reinterpret_cast<C*>(b); // FAILING!!!

从内存布局来看,C 看起来像这样(即使隐藏在远离你的地方):

class C
{
    A baseA;
    B baseB; // this is what pointer b will point to!
};

显然,在 C*B*(任一方向)之间进行转换时,我们会得到一个偏移量,static_castdynamic_cast 都会考虑到这一点,但是不是 reinterpret_cast...