将函数强制转换为基类型的指针,指向派生类型的指针的最佳方法是什么?以下为什么不自动执行?
#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的演员答案。在这个程序中,我的队列中充满了一次一个弹出的事件。除了这个队列,我有多个事件处理程序 - 根据它的派生类的类型,我将使用不同的事件处理程序的函数。因此,考虑这些事件拥有事件处理程序功能对我来说没有多大意义。实际上这让我觉得我需要重新考虑在事件中继承。如果有一些队列允许不同类型的对象,我根本不会遇到这个问题。也许这有其他原因,但我不确定。
答案 0 :(得分:2)
需要进行两项更改:
通过向virtual
类添加Base
函数来启用多态性。有一个虚拟析构函数是个好主意,所以
virtual ~Base() {};
然后,std::shared_ptr<Base>
无法自动转换为std::shared_ptr<Derived>
。您必须使用dynamic_pointer_cast
:
foo(dynamic_pointer_cast<Derived>(q.front())); // error
请同时检查是否真的需要这样做,因为不需要从基础到衍生的模型的设计通常会更好。
答案 1 :(得分:2)
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>
虽然Base
和Derived
之间存在关联,但std::shared_ptr<Base>
和std::shared_ptr<Derived>
之间没有任何关系。它们是两种不同类型的shared_ptr
。
“那么,”你可能会想,“我只会shared_ptr::get
指针。赢了!”你可以这么想,但是......不。 Derived
是Base
,但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;
}
答案 2 :(得分:1)
您需要在Base类中使用虚拟函数,否则会将其视为继承而不是多态,因此它不会引用您的带有基类指针的子对象。