C++中的多态性

Polymorphism in C++

本文关键字:多态性 C++      更新时间:2023-10-16

这是我的代码:

#include <cstdlib>
#include <iostream> 
#include <cstring>  
using namespace std;
class person {
string name;
public:
    person(const string &n){
        name=n;
    }   
    virtual person& print(const person&){}   
};
class worker:public person {
    int number;
public:
    worker(const string &n , int num ):person(n){
        number=num;
    }
    virtual worker& print(const worker& x){
        cout << number << x.number<< endl; 
        return number+=number;
    }
};
int main(int argc, char** argv) {
    person *p = new worker("john",1);
    person *g = new worker("jack",2);
    int c = p->print(*g);
    return 0;
}

所有的工人都是人,但不是所有的人都是工人。工人是人的子阶层。我的问题在于打印方法。我不知道如何正确地设计类之间的关系。

在这个代码中,结果将为空,因为主函数调用了person类的print方法。我需要的是使用多态性来调用worker的方法print。

我可以用这个:

virtual worker& print(const person& x){
        cout << number << x.number<< endl; 
    }

上面的代码调用了正确的方法,但person类中没有数字属性。所以这也不起作用。

有人能帮助我如何正确设计我的程序吗?我需要调用祖先类上的print函数,这样它就可以将调用重定向到正确的类。这是一个非常简单的例子,有更多的子类,所以它需要保持关系person>worker。

感谢任何人的帮助。

正如您已经注意到的,父类中的方法无法看到仅在其子类中定义的成员。如果你想一想,这很有意义,因为父类在编译时不可能知道它可能的子类是什么,那么它怎么可能知道它们的新数据成员呢?

正确的方法是使Person类中的print()方法纯虚拟,并为每个子类编写一个单独的print()方法,因为只有子类才能访问其私有数据成员。

virtual void print() = 0;

请注意,该函数不再接受参数,并且它在子类中的实现应该打印自己的number以及他们想要打印的任何其他成员。

这段代码很奇怪。要打印,您不需要传入personworker

class person
{
     public: virtual void print(){ cout << name; }
};
class worker : public person
{
     public: virtual void print(){ person::print(); cout << ": " << number; }
};
int main()
{
     person *p = new worker( "john", 1 ),
            *q = new worker( "jack", 2 );
     p->print();
     q->print();
     return 0;
}

您的两个print函数在返回和参数类型上都有所不同。所以他们除了名字没有任何共同点。此外,在运行时,计算机不知道Personpq指向哪种"类型"。因此,您需要给print一个统一的签名,例如:

class Person
{
public:
    virtual int print(Person* other) {}
}

我假设您希望print返回int,因为您编写了int c = p->print(*g);。我还使用了一个指针来使用变量类型作为参数。在Worker和其他派生类中,您可以编写以下内容:

int print(Person* other)
{
    Worker* worker = dynamic_cast<Worker*>(other);
    if (worker)
    {
        std::cout << number << " " << worker->number << std::endl;
        return number += worker->number;
    }
    else
    {
        // return default value and/or make some output that cast failed
        return -1;
    }
}

为了避免dynamic_cast运算符使用RTTI(运行时类型信息),不推荐使用,您可以在Person中引入一个枚举,该枚举包含派生类的类型:

class Person
{
protected: 
    enum EPersonType {WORKER /*insert other derivats here*/};
    const EPersonType Type;
    Person(EPersonType type) : Type(type) {}
    virtual int printDetails(Person* other) {}
public:
    int print(Person* other)
    {
        if (other->Type != Type)
            return -1;
        else 
            return printDetails(other);       // you can now use safe cast inhere
    }
}
class Worker : public Person
{
public:
    Worker() : Person(WORKER) {}
    int printDetails(Person* other)
    {
        Worker* worker = static_cast<Worker*>(other);  // always works
                                                       // also possible: ...= (Worker*)other;
        //...
    } 
}