虚函数的C ++多态

时间:2012-05-28 03:20:36

标签: c++ function inheritance polymorphism virtual

我正在试图弄清楚如何在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";
}

3 个答案:

答案 0 :(得分:4)

您需要将leftright设为Expr*Expr&,而不是Expr

与Java不同,C ++中类类型的变量包含实际实例,而不是对实例的引用。

所以当你这样做时:

Expr left = term();

你实际上正在调用Expr的复制构造函数,它只会创建基类Expr类的实例。

在Java中,这是非常不同的 - 你只是设置left来引用一些现有的对象,而不是创建一个新对象。

因此需要leftright成为引用或指针 - 以便在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中的所有对象确实是对堆上存储的引用,而不是对象本身。