c++ - 基本派生类成员覆盖。挑战事件11.3

标签 c++

我对学校提出挑战

class PetData 定义一个成员函数 PrintAll(),打印输出如下。提示:利用基类的 PrintAll() 函数。
姓名:Fluffy,年龄:5,ID:4444

然后他们给了我下面的代码和一个我可以修改的小片段。之间 //FIXME: 添加 PrintAll() 成员函数 和 /* 你的解决方案在这里 */ 是我添加的代码,但我没有得到正确的结果。

MyCode

// FIXME: Add PrintAll() member function
void PrintAll() {
    AnimalData data;
    data.PrintAll();
    cout << ", ID: " << idNum;
}
/* Your solution goes here  */

完整代码

#include <iostream>
#include <string>
using namespace std;

class AnimalData {
public:
   void SetName(string givenName) {
      fullName = givenName;
   };
   void SetAge(int numYears) {
      ageYears = numYears;
   };
   // Other parts omitted

   void PrintAll() {
      cout << "Name: "  << fullName;
      cout << ", Age: " << ageYears;
   };

private:
   int    ageYears;
   string fullName;
};

class PetData: public AnimalData {
public:
   void SetID(int petID) {
      idNum = petID;
   };

   // FIXME: Add PrintAll() member function
   void PrintAll(){
      AnimalData data;
      data.PrintAll();
      cout << ", ID: " << idNum;
      }
   /* Your solution goes here  */

private:
   int idNum;
};

int main() {
   PetData userPet;

   userPet.SetName("Fluffy");
   userPet.SetAge (5);
   userPet.SetID  (4444);
   userPet.PrintAll();
   cout << endl;

   return 0;
}

我得到的结果
姓名: ,年龄:-502747520,身份证:4444

我想要的结果
姓名:毛绒绒,年龄:5岁,ID:4444

最佳答案

void PrintAll(){
    AnimalData data;
    data.PrintAll();
    cout << ", ID: " << idNum;
}

AnimalData 数据; 创建一个新的、默认初始化的 AnimalData,它与属于当前 AnimalData 完全分开>宠物数据。由于您想使用已有的 AnimalData,因此丢弃此行并从下一行中删除 data。这是事情可能会出错的地方,所以我将直接跳到正确答案:要获取 AnimalDataPrintData 函数,您需要明确:

void PrintAll(){
    AnimalData::PrintAll();
    cout << ", ID: " << idNum;
}

为什么不能简单地删除数据

如果您删除要在 data 上调用 PrintAll 的对象,

void PrintAll(){
    PrintAll();
    cout << ", ID: " << idNum;
}

this 是假定的。 this 是一个 PetData,对于 PetDataPrintAll 函数的最佳匹配是当前函数。结果是无限的 recursion .

这里要吸取的真正教训是在重复使用标识符时要小心。在这种情况下,PetData::PrintAll 隐藏了 AnimalData::PrintAll,将其替换为 PetData。该函数不是 virtual,在这种情况下您不希望 virtual,因此您不会获得覆盖。您可以很容易地意外地对函数和变量执行此操作,从而导致混淆程序正在使用哪个。

一种(可能)更好的方式来构建这个程序

同时利用继承和多态性

#include <iostream>
#include <string>
using namespace std;

class AnimalData
{
public:
    virtual ~AnimalData() {}; // with polymorphism you must make sure the 
                              // correct destructor is always called.
                              // Derived classes will override this 
                              // destructor whether you explicitly define 
                              // them or not. 
    void SetName(string givenName)
    {
        fullName = givenName;
    }
    void SetAge(int numYears)
    {
        ageYears = numYears;
    }

    // virtual function. Derived classes can, but do not have to, replace 
    // this function with a version better suited to the derived class
    virtual void PrintAll()
    {
        cout << "Name: " << fullName;
        cout << ", Age: " << ageYears;
    }

private:
    int ageYears;
    string fullName;
};

class PetData: public AnimalData
{
public:
    void SetID(int petID)
    {
        idNum = petID;
    }

    // Replacing virtual function. Note if the base class function is 
    // virtual, then child class overrides are automatically virtual
    void PrintAll() override // override keyword notifies with a compiler 
                             // error if the function does NOT override when 
                             // it should.
    {
        AnimalData::PrintAll(); // call base class version for basic data
        cout << ", ID: " << idNum; // adding derived class-specific stuff
    }

private:
    int idNum;
};

// can add WildData here to handle wild animals.

int main()
{
    PetData userPet;

    userPet.SetName("Fluffy");
    userPet.SetAge(5);
    userPet.SetID(4444);
    userPet.PrintAll();
    cout << endl;

    // add an vanilla animal for demo
    AnimalData generic;
    generic.SetName("Fang");
    generic.SetAge(7);
    generic.PrintAll();
    cout << endl;

    // demonstrate polymorphism
    AnimalData * ptr = & generic;
    ptr->PrintAll();
    cout << endl;

    ptr = & userPet;
    ptr->PrintAll(); // runtime calls the correct PrintAll function
    cout << endl;

    return 0;
}

关于c++ - 基本派生类成员覆盖。挑战事件11.3,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54912617/

相关文章:

c++ - Arduino:将函数传递给类,返回字符串

c++ - 更新 Vector 中对象的属性

c++ - 如何使用 memset 将指向内存的指针设置为 NULL?

c++ - 即使使用 ios::binary 也无法以二进制模式写入文件

java - 以C/C++和其他语言重现Java原语hashCode逻辑的库

c++ - 为什么这个 C++ 函数会产生困惑的输出?

c++ - 哪种 C++ 构造函数风格更好?

c++ - 将参数转换为整数,并进行错误检查

c++ - cv::Mat 来自外部原始指针数据,释放自身

c++ - 0x771CC7C9 (ntdll.dll) 处未处理的异常