派生**到基**

Derived** to Base**

本文关键字:到基 派生      更新时间:2023-10-16

考虑以下代码:

#include <iostream>
using namespace std;
class Base
{
public:
    int foo;
};
class Derived : public Base
{
public:
    float bar;
};
int main()
{
    Base** baseArr = new Base*[30];
    for (int i=0; i<30; i++)
    {
        Derived* derived = new Derived();
        derived->foo = i;
        derived->bar = i * 2.5;
        baseArr[i] = derived;
    }
    //Notice this!
    Derived** derivedArr = (Derived**)(baseArr);
    for (int i=0; i<30; i++)
        cout << "My Base " << i << ": " << derivedArr[i]->foo << ", " << derivedArr[i]->bar << endl;
    return 0;
}

做这个数组到数组的强制转换安全吗?指针的大小在整个程序中是相同的,所以听起来我不会得到任何填充错误。但是,我知道这样做的正确方法是遍历每个元素并单独进行类型转换。

然而,我试图利用这种类型的转换来移动我的模板公共函数实现使用非泛型私有函数返回数组。cpp文件,所以我可以肯定,我的Base数组将只包含特定的Derived指针。

private:
    Base** Find(function<bool(Base*)> Predicate, int& N); //Implemented in .CPP
public:
    template <class T> T** FindByType(int &N) //T is derived from Base
    {
        //Safe?
        return (T**)(Find(
            [](Base* b)->bool { return typeid(T) == typeid(b); },
            N));
    };

当然,这只是一个简化的例子。在这种情况下,我有很多理由使用RTTI。N用于控制数组的大小。

我想知道这种不安全的cast是否会与多继承失败,例如Derived类也会继承OtherBase,我想转换为OtherBase**,我也想知道我是否有机会达到未定义的行为,或者如果我决定使用这个结构,我可能会遇到任何潜在的问题。

不,不安全。

指向Derived的指针和指向Base的指针是不一样的。指向Derived的指针可以转换为指向Base的指针,但最终结果是一个不同的指针。

由于指向Derived的指针与指向Base的指针不是一回事,因此指向Derived的指针也与指向Base的指针不是一回事。

不,这是不安全的。

如果程序试图通过非下列类型的glvalue访问对象的存储值,则该行为未定义:

  • 对象的动态类型,
  • 对象动态类型的cv限定版本,
  • 与对象的动态类型相似的类型(定义见4.4),
  • 与对象的动态类型对应的有符号或无符号类型的类型,
  • 有符号或无符号类型,对应于对象动态类型的cv限定版本,
  • 聚合或联合类型,在其元素或非静态数据成员(递归地包括子聚合或包含联合的元素或非静态数据成员)中包含上述类型之一,
  • 是对象动态类型的基类类型(可能是cv限定的),
  • charunsigned char类型。

无耻地从Ben那里偷来

在将Base**转换为Derived**的情况下,这些情况都不成立。