我尝试了两种不同的方法从基指针获取指向派生类的指针。一种方法是:

struct BaseClass {
protected:
    int offset_of_derived;
public:
    template <typename T>
    T* getAs() { return (T*)((char*)this + offset_of_derived); }
protected:
    char* getBasePtr() { return (char*)this; }
};

template <typename T>
struct DerivedClass : BaseClass
{
    DerivedClass() : BaseClass() { this->offset_of_derived = (char*)this - BaseClass::getBasePtr();  }

};

而且没有必要,std::launder因为我所做的只是从 char 进行转换并返回,以及从 Base – Derived 进行转换,对吗?

6

  • 6
    如果您知道有一个派生对象,那么static_cast将完成该工作,否则使用dynamic_cast。鉴于上述情况,我想我不明白这个问题。


    – 


  • 我认为,如果你有多个继承层次,这两种方法都行不通。如果你需要处理多重继承或菱形继承,我也不禁想到这将如何工作。


    – 

  • 1
    一般来说,希望您已经知道,每当您觉得需要进行旧的 C 风格显式转换(强制转换为char*)时,您都应该将其视为您可能做错了什么的迹象。您要解决的实际和潜在问题是什么?只是简单的向下转换?那么为什么不能使用 @RichardCritten 提到的 C++ 强制转换运算符?


    – 

  • 2
    最好的方法是根本不需要强制转换为派生类,而是使用基类中的适当虚拟函数为您完成工作。可移植代码也不应该假设任何有关 vtable 或其布局/偏移量的信息。总而言之,您现在似乎只是在试图超越自己。所以回到基础,记住 Liskov 原则,并在某个地方使用纯抽象基类重新设计您的继承结构。


    – 


  • 2
    仅供参考:它演示了一个derived_cast()函数模板,该模板static_cast()在可能的情况下应用,dynamic_cast()否则应用。这在您知道基类指针指向某个派生类的实例(或为nullptr)的情况下非常方便。dynamic_cast如果涉及虚拟继承,则需要。


    – 


最佳答案
1

“从基类型指针获取派生类的最佳方法是什么?”

您似乎试图手动实现该语言已经提供的功能。

您可以使用两种相关的语言结构:

  1. 最强大的(但由于运行时检查,效率稍低)是。它:

    沿着继承层次结构安全地向上、向下和横向转换对类的指针和引用。

    如果你不确定层次结构中的对象类型,只需使用dynamic_cast。如果你请求的转换无效,它将返回一个空指针,因此你可以随时检查自己。

  2. 如果您确定该对象实际上是派生对象,则可以使用static_cast(不会引起运行时检查):

    向下转型也可以用 static_cast 来执行,这样可以避免运行时检查的成本,但只有当程序可以保证(通过其他逻辑)表达式指向的对象肯定是 Derived 时才是安全的。

    请注意,如果您使用的static_cast对象不是预期的派生对象,则行为未定义。

用法示例dynamic_cast

BaseClass * p1 = get_object_pointer();  // some function that returns a pointer to an object in the hirarchy
DerivedClass * p2 = dynamic_cast<DerivedClass*>(p1);  // p2 will be a null pointer if conversion is invalid

用法示例static_cast

BaseClass * p1 = new DerivedClass;
DerivedClass * p2 = static_cast<DerivedClass*>(p1);  // OK - we know p1 points to DerivedClass

或者如果您想将其作为方法模板,BaseClass那么按照您可以添加:

template <typename T> 
T* getAs() { return dynamic_cast<T*>( this ); } // or use `static_cast` under the limitations explained above