当前位置: 首页 > 知识库问答 >
问题:

分配给派生类和多态性的基类指针

史俊德
2023-03-14

对于下面的代码,当基类指针被分配给派生类时,我有关于多态性的问题。

当派生类的对象直接使用print函数时,输出是显而易见的。

当我使用基类指针并指向派生类的对象时,会使用基类的print函数,但输出的是派生对象的信息。有人能详细解释一下吗?谢谢!

class Person {
public:
    Person() {};
    Person(string nm):name(nm) {};
    void print() const;
private:
   string name;
};

class Student : public Person {
public:
    Student(int num, string nm) : IDNumber(num), Person(nm) {};
    void print() const;
private:
    int IDNumber;
}

class Employee : public Person {
public:
    Employee(int num, int sal, string nm) : IDNumber(num), salary(sal), Person(nm) {};
    void print() const;
private:
    int IDNumber, salary;
}

void Person::print() const {
    cout << name << endl;
}

void Student::print() const {
    cout << "GoGoGo! ";
    Person::print();
}

void Employee::print() const {
    cout << "I work: ";
    Person::print();
}

int main() {
    Person per("Peter");
    Student stu(3141, "Sally");
    Employee emp(2718, 40, "Edward");

    Person* ptr = &per;
    Person* ptr2 = &stu;
    Person* ptr3 = &emp;

    per.print();   //Peter
    stu.print();   //GoGoGo! Sally
    emp.print();   //I work: Edward

    ptr->print();  //Peter
    ptr2->print(); //Sally
    ptr3->print(); //Edward
    return 0;
}

共有2个答案

殳睿
2023-03-14

代码行为的关键词是“静态绑定和动态绑定”。

当编译器在编译时读取下面的语句时,它看到ptr3是person类型的,它检查Person类并用Person类中定义的print函数地址替换print()。所有这些都发生在编译时,这就是为什么叫做静态绑定。

ptr3->print();

为什么它能够打印通过派生类对象输入的信息?

在下面的语句中,您调用基类的构造函数并在基类成员中输入信息。ptr3*属于基类类型,因此它可以访问其成员。

Employee(int num, int sal, string nm) : IDNumber(num), salary(sal), Person(nm) {};

如果,你赚了int工资;员工类中的公共成员,并尝试通过以下方式访问

ptr3-

它会给出错误

ptr3没有指定薪金的成员

因为salary是派生类的成员,基类对象无法访问它。

缪茂勋
2023-03-14

函数< code>print()不是< code >虚拟的,因此不是多态的。基类上的函数隐藏了子类的函数。

要使代码按预期工作,您唯一要做的就是在类< code>Person中使< code>print()成为虚拟的:

class Person {
public:
    Person() {};
    virtual ~Person() {};
    Person(string nm):name(nm) {};
    virtual void print() const;
private:
   string name;
};

请注意,我添加了一个虚拟析构函数,这是每个要继承的类所必需的。

输出显示了派生对象的信息,因为子类继承了基类的成员(即< code>name,它被设置为Peter、Sally和Edward)。

 类似资料:
  • 首先,我不确定如何准确地用一行来描述我在做什么...因此标题有点模糊。 我能给出的问题的最短描述是“我有一个函数,它应该能够将许多可能的类类型中的任何一个作为参数,这些类都是从基类派生的”。 具体来说,我有两个类别的类,它们都实现了不同类型的方法,它们很相似,但不完全相同。 也许我只是举个例子会更好?你会看到我用指针类型转换做了一些稍微奇怪的事情。我不认为这些是好的编程实践。它们至少有点奇怪,我想

  • 一个类的对象经常会是另一个类的对象。例如,矩形当然是四边形(正方形、平行四边形和梯形也是这样),因此可以说矩形类 Rectangle 是从四边形类 Quadrilateral 继承而来的。在本例中,类 Quadrilateral 叫做基类,类 Rectangle 称为派生类。矩形是四边形的一种特殊类型,但是要说四边形是矩形则是不正确的。图 9.1 示例了几个简单的继承例子。 基类 派生类 stud

  • 从已有的对象类型出发建立一种新的对象类型,使它部分或全部继承原对象的特点和功能,这是面向对象设计方法中的基本特性之一。继承不仅简化了程序设计方法,显著提高了软件的重用性,而且还使得软件更加容易维护。派生则是继承的直接产物,它通过继承已有的一个或多个类来产生一个新的类,通过派生可以创建一种类族。   继承 基本概念 在定义一个类A时,若它使用了一个已定义类B的部分或全部成员,则称类A继承了类B,并称

  • 我无法将派生类传递给接受基类作为参数的函数。基类由“障碍物”组成,这些障碍物将被放置在“板”上。无效的board::setvalue(int-length、int-width、board 但是,这会导致编译器给出“未知参数转换…”错误。在浏览站点时,我发现我应该将派生对象作为常量进行传递,但这会导致问题,因为无法将常量分配给线路板(因为它包含指向非常量障碍物的指针)。 反过来,将线路板更改为包含常

  • 假设我有一个没有数据的类: 和派生类 Empty类的对象的大小为1。派生类的空部分的大小通常为0。据我所知,编译器看到基Empty类没有数据,因此它可以优化Empty的大小,以防它“在”Derived中,但标准并不要求这样做。 所以问题是: 我能在编译时确定Derived类的Empty部分并没有占用内存吗。 我知道我可以像一样进行检查...但它太冗长了,并且有几个类,如派生。有没有更优雅的解决方案