繁体   English   中英

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

[英]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 但是,这可能不会将参数强制为Derived类,这是我正在编写的程序中唯一的内容。

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

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

编辑:一些人建议我使用虚函数。 我想象他们的意思是我应该将foo作为如下的虚函数放入类中。 但是,如果我错了,请更正我的理解。

#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的强制转换答案。 在此程序中,我的队列中充满了每次弹出一个事件。 除了该队列之外,我还有多个事件处理程序-根据派生类的类型,我将使用其他事件处理程序的功能。 因此,考虑这些事件具有事件处理程序功能对我来说没有多大意义。 实际上,这使我认为我需要重新考虑在事件中完全继承。 如果有一些队列允许不同类型的对象,我将根本不会遇到这个问题。 不过,由于其他原因,这可能很糟糕,我不确定。

需要进行两项更改:

通过向Base类添加virtual函数来启用多态。 最好有一个虚拟析构函数,所以

virtual ~Base() {};

然后,无法将std::shared_ptr<Base>自动转换为std::shared_ptr<Derived> 您必须使用dynamic_pointer_cast

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

还请检查是否确实需要这样做,因为通常不需要从基础到派生的强制转换的设计会更好。

在线工作代码

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

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

q.front()

将返回一个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两种不同类型。

“好吧,”您可能会想,“我只是shared_ptr::get指针拿出来。赢了!” 您可以认为,但是...不。 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;
}

您需要在基类中有一个虚函数 ,否则它将把它视为继承而不是多态,因此它不会用基类指针引用子对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM