为什么函数不能正确转换指针(从基 class 到派生 class)

Why doesn't the function cast a pointer correctly (from base class to derived class)

让函数将指针转换为基类型指针或派生类型指针的最佳方法是什么?为什么以下不自动工作?

#include <iostream>
#include <memory>
#include <queue>

class Base{
public:
    Base() {};
};

class Derived : public Base{
public:
    Derived() : Base() {};
};

void foo(const std::shared_ptr<Derived>& dp){ // "wrong" signature
    std::cout << "it runs\n";
}

int main(int argc, char **argv)
{
    std::queue<std::shared_ptr<Base>> q;
    q.push( std::make_shared<Derived>() );
    foo(q.front()); // error

    return 0;
}

用以下作品替换foo。然而,这可能不会将参数强制为派生 class,这是我正在编写的程序中唯一应该存在的东西。

void foo(const std::shared_ptr<Base>& dp){
    std::cout << "it runs\n";
}

我可能还可以手动投射指针。还有其他想法吗?

编辑: 一些人建议我使用虚函数。我想他们的意思是我应该把 foo 作为虚函数放在 class 中,如下所示。不过,如果我说错了,请指正我的理解。

#include <iostream>
#include <memory>
#include <queue>

class Base{
public:
    Base() {};
    virtual void foo () { std:: cout << "base\n"; };
};

class Derived : public Base{
public:
    Derived() : Base() {};
    void foo() {std::cout << "derived\n";};
};

int main(int argc, char **argv)
{
    std::queue<std::shared_ptr<Base>> q;
    q.push( std::make_shared<Derived>() );
    q.front()->foo();

    return 0;
}

编辑 2: 谢谢大家的帮助。目前我已经接受了一个答案,但在我的真实程序中,实际上我可能会倾向于使用@alain 的铸造答案。在这个程序中,我的队列中充满了我一次弹出一个事件。除了这个队列之外,我还有多个事件处理程序——根据派生 class 的类型,我将使用不同的事件处理程序函数。因此,考虑这些事件拥有事件处理程序功能对我来说没有多大意义。实际上,这让我觉得我需要重新考虑在事件中完全继承。如果有一些队列允许不同类型的对象,我根本不会有这个问题。不过,也许由于其他原因这很糟糕,我不确定。

您的 Base class 中需要有一个 Virtual Function 否则它将被视为 Inheritance 而不是 Polymorphism 所以它不会用基 class 指针引用你的子对象。

需要进行两项更改:

通过将 virtual 函数添加到 Base class 来启用多态性。有一个虚拟析构函数是个好主意,所以

virtual ~Base() {};

那么,std::shared_ptr<Base>不能自动转换为std::shared_ptr<Derived>。你必须使用 dynamic_pointer_cast:

foo(dynamic_pointer_cast<Derived>(q.front())); // error

另请检查这是否真的需要,因为不需要从基到派生的转换的设计通常更好。

Working code online

std::queue<std::shared_ptr<Base>> q;

是指向 Base 的(共享)指针队列,因此

q.front()

将return一个std::shared_ptr<Base>

void foo(const std::shared_ptr<Derived>& dp)

需要 std::shared_ptr<Derived>

虽然 BaseDerived 之间存在关系,但 std::shared_ptr<Base>std::shared_ptr<Derived> 之间没有关系。它们是两种不同类型的 shared_ptr.

"Well then," 你可能会这么想,"I will just shared_ptr::get the pointer out. Winning!" 你可能会这么想,但是……不。 DerivedBase,但 Base 不是 Derived

此时你有两个选择:将 Base 转换为 Derived 因为你很清楚它是 Derived,但这只在玩具代码中才真正可行你确实知道它是 Derived。真正的代码变得更加混乱。这是个坏主意。

让我们直接跳到好主意,好吗?虚拟功能。

#include <iostream>
#include <memory>
#include <queue>

class Base
{
public:
    // none of the constructors do anything, so I got rid of them.
    // code that's not there has no bugs.
    virtual ~Base() = default; // must provide virtual destructor so that
                               // correct destructors get called when a Base
                               // is destroyed
    virtual void foo() = 0; // pure virtual function. All descendants must
                            // provide this function
                            // Pure virtual has the side effect of  making 
                            // it impossible to instantiate a Base.
                            // This may or may not be what you want. If it 
                            // isn't, remove the =0 and implement the function.
/*
    virtual void foo()
    {
        std::cout << "I pity the foo who derives from Base.\n"
    }
*/
};

class Derived: public Base
{
public:
    void foo() // implement Base::foo
    {
        std::cout << "it runs\n";
    }
};


int main()
{
    std::queue<std::shared_ptr<Base>> q;
    q.push(std::make_shared<Derived>());
    q.front()->foo();

    return 0;
}