【发布时间】:2021-05-24 21:01:09
【问题描述】:
我正在设计一个简单的跟踪程序,它构建了一个指向代表动物园中动物的对象的指针向量。
我将我的向量声明为:vector<Animal*> zooAnimals,Animal* 是指向 Animal 类的指针。
问题在于从Animal 继承子类。例如,Animal 是 Mammal 的父级,而后者又是 Bat 的父级。但是,当我创建 Bat* 并将其添加到向量时,它并没有拾取它应该继承的所有其他字段。它只接收来自Animal(跟踪号和动物名称)的字段,但没有来自Mammal(type、subType 和nursingStatus)的字段。
我设置它的方式是我的程序调用一个函数createNewZooAnimal(),它创建并返回一个Animal*(指向动物类型对象的指针),通过(理论上)调用动物子的特定构造函数键入并返回指向新创建对象的指针(即Crocodile* 或Bat* 等)。但是,这些新创建的指针不是从Mammal/Oviparous 或继承自它们自己的类的特定构造函数。我的头文件似乎没有任何错误,实现它们的 cpp 文件也没有。系统会愉快地创建我需要的特定指针,但不会继承最基本的类Animal之外的任何东西。
Animal* createNewZooAnimal(int trackingNum, string name, string type, string subType, int numEggs, int nursing) {
//using a simple if-else if structure here, we cover each sub-type, calling the constructor for each to create the pointer for each object
if (subType == "Crocodile") {
Crocodile* croc1 = new Crocodile(numEggs); //calls constructor and creates a pointer to the new object of class Crocodile
croc1->trackingNum = trackingNum;
croc1->name = name;
return croc1; // returns pointer to get included in the vector
}
else if (subType == "Goose") {
Goose* goose1 = new Goose(numEggs); //calls the constructor for Goose, passing in numEggs, and assigns a pointer to the location of the new object
goose1->trackingNum = trackingNum;
goose1->name = name;
return goose1; //returns pointer to get included in the vector
}
else if (subType == "Pelican") { //constructs new pelican object and returns its pointer
Pelican* pelican1 = new Pelican(numEggs);
pelican1->trackingNum = trackingNum;
pelican1->name = name;
return pelican1;
}
else if (subType == "Bat") { //constructs new bat object and returns its pointer
Bat* bat1 = new Bat(nursing);
bat1->trackingNum = trackingNum;
bat1->name = name;
return bat1;
}
else if (subType == "Whale") { //constructs a new whale object and returns its pointer
Whale* whale1 = new Whale(nursing);
whale1->trackingNum = trackingNum;
whale1->name = name;
return whale1;
}
else if (subType == "SeaLion") { //constructs a new sea lion object and returns it pointer
SeaLion* seaLion1 = new SeaLion(nursing);
seaLion1->trackingNum = trackingNum;
seaLion1->name = name;
return seaLion1;
}
我设置的方式是用户将输入有关动物的信息(名称、跟踪号、类型(哺乳动物/卵生)、子类型(蝙蝠、鲸鱼等)...)然后通过指向指针创建者createNewZooAnimal 来调用动物子类型的特定构造函数。然后该函数返回一个指向该对象的指针,然后将其推送到向量上:
cout << "Enter 'Y' or 'y' to save this animal to the system, or 'N' or 'n' to cancel: " << endl;
cin >> addAnimalConfirm;
if (addAnimalConfirm == 'Y' || addAnimalConfirm == 'y') { // if user confirms addition of animal, parameters are passed
// to pointer return function, where a new animal object is created
// and we receive the pointer to it. This is then pushed onto our vector
// of pointers
Animal* temp = createNewZooAnimal(trackingNum, name, type, subType, numEggs, nursing);
zooAnimals.push_back(temp);
cout << "Animal added to Wildlife Zoo's system successfully." << endl;
}
这是 Animal.h 代码:
class Animal{
public:
std::string name;
int trackingNum;
Animal() {
trackingNum = 0;
name = " ";
}
};
还有 Mammal.h,例如:
class Mammal : public Animal {
public:
Mammal();
Mammal(int nursingIndicator);
void displayAnimalData();
std::string type;
std::string subType;
int getNursing();
void setNursing(int numberEggs);
private:
int nursing;
};
和 Bat.h:
class Bat : public Mammal {
public:
Bat();
Bat(int nursingIndicator);
};
【问题讨论】:
-
请发帖minimal reproducible example。有问题的部分似乎是“但是当我创建 Bat* 并将其添加到向量时,它不会在它应该继承的所有其他字段上拾取”,但该部分不在您发布的代码中。您发布的内容看起来像工厂功能,看起来还不错
-
如果您有一个指向基类型的指针,该指针指向一个更派生的对象,则不能使用该指针访问该对象的更多派生部分。如果你有一个
Animal*,那么你所知道的就是指向的对象是Animal的某种形式,所以这就是你可以访问的所有对象的Animal部分。目前尚不清楚你想用你的向量实现什么。此问题的正确解决方案取决于您要执行的操作。 -
更严重的是,存储原始指针以后可能会导致所有权问题,您应该考虑使用 smart 指针(
unique_ptr或shared_ptr)。但它们不应导致对象切片。我认为切片的出现是因为或您使用这些指针的方式。 -
为什么你认为有问题?你没有在问题中显示它。是不是你观察到内存泄漏?我认为您所展示的构建过程无法正确删除。我看到的唯一方法是通过存储在
zooAnimals中的指针,这实际上会做错事。 -
忘记向量。制作一个指向蝙蝠的动物*。现在,使用 Animal* 您可以访问 Animal 拥有的任何成员函数或数据,如果它是虚拟的,它将使用派生类代替。如果您需要特定的 Bat 东西(例如 EchoLocate() 或其他东西),您需要先知道该对象是 Bat,然后才能执行此操作 - 因此其中一个虚拟功能应该是“类型”,以便您知道自己是哪种动物正在指向。然后,您可以创建一个 Bat* 指向它并访问您想要的任何内容。
标签: c++ pointers inheritance