将指针向下转换为指针

Downcasting pointer to pointer

我正在学习 C++ 中的多态性,但我无法将指针向下转换为指针。我有一个 class Base 和一个扩展 Base 的 class Derived。我想使用一个函数 Base **derivedFactory(size_t size) 做一个 Derived 对象池。我试过 Base** array = new Derived*[size]; 但编译器说它无法从 Derived** 转换为 Base**。所以我尝试了下一个:

Base **derivedFactory(size_t size)
{
    Base* array = new Derived[size];
    
    for (size_t idx = 0; idx < size; ++idx)
    {
        Derived derived = Derived();
        array[idx] = derived;
    }
    
    Base** arrayBase = &array;
    
    return arrayBase;
}

并编译。但是当我想访问所有 Derived 对象时,main.cc 抛出 Segmentation fault (core dumped)。它执行 hello(cout) 但随后在结束循环的第一次迭代之前抛出。

你能帮帮我吗?

Main.cc

#include "main.ih"

int main()
{
    Base **bp = derivedFactory(10);

    for (size_t idx = 0; idx <= 10; ++idx)
    {
        bp[idx]->hello(cout);
        cout << "Not printing\n";
    }
}

Class基数:

class Base
{
    private:
        virtual void vHello(std::ostream &out)
        {
            out << "Hello from Base\n";
        }
    public:
        void hello(std::ostream &out)
        {
            vHello(out);
        }
};

Class 导出:

class Derived : public Base
{
    std::string d_text;

    private:       
        void vHello(std::ostream &out) override
        {
            out << d_text << '\n';
        } 

    public:
        Derived()
        {
            d_text = "hello from Derived";
        }
        
        virtual ~Derived()
        {}
};

谢谢!

显示的代码存在多个基本问题。

   Base* array = new Derived[size];

这将创建一个 Derived 对象数组。 C++ 中的这种数组由指向数组中第一个值的指针表示。在这种情况下,这将是一个 Derived *,这是您从 new.

得到的

在 C++ 中,将指向派生 class 的指针向下转换为指向基 class 的指针是有效的。

但仅此而已。这就是你得到的。

这并不意味着可以将指向数组中第一个派生对象的指针向下转换为指向基 class 的指针,然后使用指向基 class 的指针访问实际数组中的每个派生对象。指针在 C++ 中不是这样工作的。尝试访问指针指向的第一个对象以外的任何其他对象是未定义的行为。这是所示代码的第一个基本问题。

Base** arrayBase = &array;

array 是在此函数中声明为本地对象的对象。当此函数 returns, array 被销毁时,就像此函数中声明的任何其他变量一样。它会被摧毁。不会了。它将不复存在。它将渴望峡湾。它将成为一个前对象。

显示的代码尝试获取此对象的地址,并从该函数中 return 它。在函数 returns 之后,this 指针成为指向已销毁对象的指针,任何访问它的尝试都将是未定义的行为。

正确地做到这一点需要一种完全不同的方法。与其使用 new 创建派生对象数组,不如使用 new 创建指向基础对象的指针数组。然后,每个指针都通过 newing 一个单独的派生对象单独初始化,例如:

 Base **array = new Base *[size];

 // ...

 array[i] = new Derived{};