我正在试图弄清楚如何在C ++中处理继承和多态,它似乎与我在Java中习惯的有点不同。我试图在其中一个函数中返回一个基类,但是当收到返回时,我希望该对象是派生类。然而,它并没有像我预期的那样成功。
#include "Prefixer.h"
using namespace std;
Prefixer::Prefixer( Lexer l ){
lexer = l;
}
Expr Prefixer::expr() {
Expr left = term();
Expr right = termTail();
cout << left.name();
cout << right.name();
return left;
}
Expr Prefixer::term() {
NullExpr temp;
return temp;
}
Expr Prefixer::termTail() {
NullExpr temp;
return temp;
}
但返回的left.name()和right.name()都调用Expr(基类)虚拟名称()函数:C。我怎样才能使它们从派生类NullExpr中调用重载的name()函数?
string Expr::name() {
return "expr";
}
string NullExpr::name() {
return "null";
}
答案 0 :(得分:4)
您需要将left
和right
设为Expr*
或Expr&
,而不是Expr
。
与Java不同,C ++中类类型的变量包含实际实例,而不是对实例的引用。
所以当你这样做时:
Expr left = term();
你实际上正在调用Expr
的复制构造函数,它只会创建基类Expr
类的实例。
在Java中,这是非常不同的 - 你只是设置left
来引用一些现有的对象,而不是创建一个新对象。
因此需要left
和right
成为引用或指针 - 以便在C ++中使用Java进行相同的操作。
答案 1 :(得分:2)
您的问题始于以下代码:
Expr Prefixer::term()
{
NullExpr temp;
return temp;
}
temp
是一个局部变量,在函数末尾被销毁。返回值通过复制返回表达式Expr
来生成temp
实例(因为这是返回类型)。调用者永远不会看到NullExpr
对象。
Java的作用基本上是:
Expr* Prefixer::term()
{
NullExpr* temp = new NullExpr;
return temp;
}
但是你不能盲目地在C ++中这样做,否则你最终会遇到内存泄漏(Java有垃圾收集器,C ++没有)。您可以使用delete
:
Expr* left = term();
left->name();
delete name;
更推荐的方法是使用智能指针,当指针的最后一个指针消失时自动销毁该对象:
shared_ptr<Expr> Prefixer::term()
{
NullExpr* temp = new NullExpr;
return temp;
}
答案 2 :(得分:0)
要使用方法dynamic-binding
(或调用带有基础对象句柄的重载子类方法),您应该使用引用或指针操作对象。如果这样实现,请确保返回对象的生命周期足够长,以便在方法终止后访问它。您发现它与Java不同,因为Java中的所有对象确实是对堆上存储的引用,而不是对象本身。