简体   繁体   English

虚拟函数上的C ++多态

[英]C++ Polymorphism on Virtual Functions

I'm trying to figure out how inheritance and polymorphism is handled in C++, it seems its a little different than what I'm used to in Java. 我试图弄清楚如何在C ++中处理继承和多态性,这似乎与我在Java中所使用的有所不同。 I'm trying to return a base class in one of the functions, but when the return is received, I would like the object to be the derived class. 我试图在其中一个函数中返回基类,但是当接收到返回值时,我希望对象成为派生类。 However it is not working out as expected for me. 但是,它没有达到我的预期。

#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;
}

But the returned left.name() and right.name() both calls the Expr's (the base class) virtual name() function :C. 但是返回的left.name()和right.name()都调用Expr的(基类)虚拟name()函数:C。 How can I make it so that they call the overloaded name() functions from the derived class NullExpr? 如何使它们从派生类NullExpr中调用重载的name()函数?

string Expr::name() {
    return "expr";
}

string NullExpr::name() {
    return "null";
}

You need to make left and right be Expr* or Expr& , not Expr . 你需要让leftrightExpr*Expr& ,而不是Expr

Unlike Java, variables of a class type in C++ hold actual instances, not references to instances. 与Java不同,C ++中类类型的变量保存实际实例,而不是实例的引用。

So when you do: 因此,当您这样做时:

Expr left = term();

you are actually calling Expr 's copy constructor, which will only make an instance of the base Expr class. 您实际上是在调用Expr的副本构造函数,该构造函数仅构成基本Expr类的实例。

In Java, that's very different -- there you're just setting left to refer to some existing object, not creating a new. 在Java中,这是非常不同的-您只需要设置left以引用一些现有对象,而不创建新对象。

Thus the need to have left and right be references or pointers -- so that the same thing happens in C++ that you're using to happening in Java. 因此,需要有leftright是引用或指针-让同样的事情发生在C ++中,您使用在Java中发生的事情。

Your problem starts in this code: 您的问题从以下代码开始:

Expr Prefixer::term()
{
    NullExpr temp;
    return temp;
}

temp is a local variable, destroyed at the end of the function. temp是一个局部变量,在函数末尾销毁。 The return value makes an Expr instance (because that's the return type) by copying the return expression, temp . 通过复制返回表达式temp ,该返回值构成一个Expr实例(因为这是返回类型)。 The caller never sees a NullExpr object. 调用者从不会看到NullExpr对象。

What Java does is essentially: Java的本质是:

Expr* Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}

but you mustn't blindly do that in C++, or you'll end up with memory leaks (Java has a garbage collector, C++ doesn't). 但是您一定不能盲目地在C ++中这样做,否则最终会导致内存泄漏(Java有垃圾收集器,而C ++没有)。 You can free the memory using delete : 您可以使用delete释放内存:

Expr* left = term();
left->name();
delete name;

A more recommended approach is to use smart pointers that automatically destroy the object when the last pointer to it disappears: 推荐的方法是使用智能指针,当指向该对象的最后一个指针消失时,该指针将自动销毁该对象:

shared_ptr<Expr> Prefixer::term()
{
    NullExpr* temp = new NullExpr;
    return temp;
}

To use the method dynamic-binding (or invoke overloaded subclass method with a handle to base object) you should manipulate object with reference or pointer. 若要使用dynamic-binding方法(或使用基对象的句柄调用重载子类方法),则应使用引用或指针来操作对象。 If implemented like that, make sure the life of your returned object is long enough, so you can access it after the method terminates. 如果这样实现,请确保返回的对象的寿命足够长,以便在方法终止后可以对其进行访问。 You find it's different from Java, because all object in Java is indeed a reference to a storage on heap, instead the object itself. 您会发现它与Java不同,因为Java中的所有对象确实是对堆上存储的引用,而不是对象本身。

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

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