C++ 安全地将指向前向声明类的指针强制转换为C++;?

C++ 安全地将指向前向声明类的指针强制转换为C++;?,c++,pointers,casting,C++,Pointers,Casting,在一个头文件中,我有: #include "BaseClass.h" // a forward declaration of DerivedClass, which extends class BaseClass. class DerivedClass ; class Foo { DerivedClass *derived ; void someMethod() { // this is the cast I'm worried about. ((Base

在一个头文件中,我有:

#include "BaseClass.h"
// a forward declaration of DerivedClass, which extends class BaseClass.
class DerivedClass ;
class Foo {
   DerivedClass *derived ;
   void someMethod() {
       // this is the cast I'm worried about.
       ((BaseClass*)derived)->baseClassMethod() ;
   } 
};
现在,DerivedClass(在它自己的头文件中)是从基类派生的,但是编译器在读取上面关于类Foo的定义时不知道这一点。然而,Foo指的是DerivedClass指针,而DerivedClass指的是Foo指针,所以它们不能同时知道对方的声明

第一个问题是在没有定义派生类的完整定义的情况下,是否安全(根据C++规范,而不是在任何给定编译器中)将派生类指针转换到基类指针类型。


第二个问题是是否有更好的方法。我知道我可以将someMethod()的主体移出类定义,但在这种情况下,它必须是内联的(实际测量热点的一部分-我不是猜测)。

这里的内容是用C++的术语重新解释转换(因为“已知是安全的”
静态转换将导致编译器错误),我会非常怀疑的


难道不可能为派生对象转发声明Foo吗?

它可能会起作用,但风险是巨大的

问题是,大多数情况下,
Derived*
Base*
在引擎盖下确实具有相同的值(可以打印)。然而,一旦您有了虚拟继承和多重继承,这就不是真的,而且标准肯定不能保证这一点

使用
static\u cast
时,编译器会执行必要的算法(因为它知道类的布局)来调整指针值。但是这种调整不是由重新解释转换或C型转换执行的

现在,您可以像这样完美地重新编写代码:

// foo.h
class Derived;

class Foo
{
public:
  void someMethod();
private:
  Derived* mDerived;
};

// foo.cpp
#include "myProject/foo.h"

#include "myProject/foo.cpp"

void Foo::someMethod() { mDerived->baseClassMethod(); }
无论如何:您使用的是一个指向
派生的
的指针,虽然这没关系,但您应该注意到一些问题:特别是如果您打算
新建
类的实例,则需要重新定义
复制构造函数
,类的
赋值运算符
析构函数
,以正确处理指针。还要确保初始化每个
构造函数中的指针值(无论是NULL还是派生的
实例)


文档本身不是不可能的。

你应该使用C++风格的演员,而不是C风格。原因是,你所做的实际上是一个重新解释,这是,除了一些罕见的用途,几乎普遍不安全

您正在执行的演员阵容没有正确执行。您可能能够安全地在两者之间转换,这是实现定义的(标准仅保证void*能够保存指向任何类型的指针),但是如果您在之后实际使用新指针,您将召唤鼻恶魔

大多数时候,这些鼻魔是良性的,你不会注意到它们(在相当数量的实现中)。但是,如果您使用多重继承,这些同样的鼻恶魔将变得非常狡猾。即便如此,你也不应该把未定义的行为视为“安全”或其他任何本质上不好的行为,除非根本没有其他方法可以得到你所需要的(作为一名专业人士,我从来没有遇到过)


这就引出了不使用c样式转换的全部原因。有一些非常,非常少,非常罕见的情况下,你必须,但作为一名专业人士,我从来没有遇到过一个。c风格强制转换的问题在于,它们会根据情况的语义悄悄地更改为不同类型的强制转换。在代码的不同区域中的微小代码更改可能会在您不知情的情况下严重改变强制转换操作。一个C++风格的演员会通知你,当语义改变了需要一个不同类型的演员时,一个C型演员会简单地默默地改变;使用c样式转换时,您可以从已定义的行为转换为未定义的行为,而不需要任何提示。

我建议使用c++的转换运算符,而不是c样式转换。你会遇到更少的麻烦,编译器会给你更多的信息。在这里,编译器正在执行一个
重新解释\u cast
,这几乎肯定不是您想要的。如果您希望函数是
内联的
,请将其标记为
内联的
。不需要在类中定义它。您仍然可以在头文件中定义它,以便该定义在包含该头文件的任何TU中都可用。编译器实际内联它的可能性可能与您在类定义中定义它的可能性一样。在这两种情况下都不能保证它是内联的。@SteveJessop也许想要一个简单的示例代码来澄清这个问题?