我在SO上发现了许多类似的问题,但是它们的解决方案要么无效,要么略有不同(通常使用指针代替,我不想更改caller()签名!)。如果已经问过(并回答了),请告诉我,我将删除此问题。
我发现了一种叫做 visitor模式的东西,但我很好奇是否有一个更简单的解决方案。我尝试不使用virtual
来做,因为我的课程还没有介绍。还是我在这里需要它?
我有以下代码:
class Base
{
public:
void fun(); // cout << "Base"
};
class Derived : public Base
{
public:
void fun(); // cout << "Derived"
};
void caller(Base &obj) // must stay as it is
{
// here i want to call Derived::fun()
// obj.fun() prints 'Base' but I need 'Derived'
}
int main()
{
// Base base;
// caller(base);
// EDIT:
Derived derived;
caller(derived);
}
将Base &
传递给函数caller()时,让caller()调用Derived :: fun()而不是Base :: fun()的最简单方法是什么?
如果有一个简单的答案向我指出正确的方向,将不胜感激,我已经在这上面停留了一段时间:)
我知道您不会在生产代码中这样做,这是关于学习C ++的
编辑:我将调用者函数参数更改为类型Derived
而不是Base
答案 0 :(得分:3)
Derived
类对象上调用Base
成员函数。每个Derived
都是Base
,但是Base
不是Derived
。换句话说,Derived
可能具有Base
缺乏的一堆信息。 您可以在Base
类对象上调用Derived
成员函数,但不能相反。
换句话说...
class Base {
public: void b_thing() { }
};
class Derived : public Base {
public: void d_thing() { }
};
int main() {
Base b;
Derived d;
d.b_thing(); // Okay!
b.d_thing(); // Bad :(
}
但是,您可以有一个引用Base
对象的Derived
引用:
Base &b_ref = d;
由于这实际上是一个Derived
对象,因此可以通过多态调用它调用Derived
成员函数(在virtual
中被声明为Base
):
class Base {
public: virtual int thing() { return 0; }
};
class Derived : public Base {
public: int thing() { return 1; }
};
int caller(Base &obj)
{
return obj.thing(); // Returns 1 if obj actually references a Derived object
}
int main() {
Base b;
Derived d;
caller(d); // 1
caller(b); // 0
}
但是,请注意,当传递Base
对象时(实际上obj
引用Base
对象时),我们仍然调用Base
成员函数。
答案 1 :(得分:2)
不能。 MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE (p)-[:DIRECTED]->(m)
WITH p, m
MATCH (p)-[:ACTED_IN]->(m2:Movie {title: 'Movie X'})
RETURN p, m, m2
被引用为实际的caller
对象。在C ++中,无法将其转换为对Base
对象的引用(因为该对象实际上不是Derived
对象)。任何尝试进行转换的行为都会被未定义行为所犯规。这意味着任何事情都可能发生。具体而言,该呼叫可能似乎有效-除非您要向主要客户进行演示,否则此时它将格式化您的硬盘。 (出于夸张的目的,这有点夸张;但是未定义的行为已经将for循环运行到64,变成无限循环。)
如果我们稍微更改Derived
,那么这将成为一个更有趣的问题:
main
现在我们可以安排致电int main()
{
Derived derived;
caller(derived);
}
。 最佳解决方案是使Derived::fun
成为虚拟函数。然后就可以了:
fun
对class Base
{
public:
virtual void fun() { cout << "Base"; }
};
的调用将定向到obj.fun
(如您所愿),并且代码将打印“派生”。
那太好了-绝对应该是您的第一通电话。但是,也许您无法更改Derived::fun
。在这种情况下,任何功能(例如析构函数)是否是虚拟的?如果是这样,我们可以使用Base
:
dynamic_cast
对此的好处是,如果void caller(Base &obj) // must stay as it is
{
Derived& d_ref = dynamic_cast<Derived&>(obj);
d_ref.fun();
}
实际上不是 一个obj
对象,则dynamic_cast将抛出Derived
,而您不会获得不确定的行为。
最后,也许您无法更改std::invalid_cast
,和,没有虚函数。在这种情况下,您唯一的选择是触及Base
的大手笔-但是,请注意,这是C ++程序员不但要自发自足,而且要整条脚踢。 (它不如static_cast
的等离子大炮那么糟糕,但是除非您必须这样做,否则您真的不想这样使用它。)
reintepret_cast
一个人可能必须在生产代码中写这种东西,但是void caller(Base &obj) // must stay as it is
{
Derived& d_ref = static_cast<Derived&>(obj);
d_ref.fun();
}
通常有某种“我是什么样的人”指示符,您可以在使用Base
之前进行检查