作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图实现的是创建子类对象的父类(super class)数组。
在我正在进行的这个特定测试中,我想要一个动物数组,其中包含一些狗obj和一些猫obj,同时它们保持其属性。
#include <iostream>
using namespace std;
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
//MAIN
int main(int argc, char* argv[])
{
animal** test;
animal* p;
for (int i = 0; i < 6; i++)
{
p = new dog;
p++;
}
cout << "\n";
for (int i = 0; i < 6; i++)
{
p = new cat;
p++;
}
cout << "\n";
test = &p;
cout << (*test-7)->get_ID();
return 0;
}
到目前为止,我了解到的是p不是数组,它通过循环不断指向不同的内存地址。
animal** test = new dog[6];
,因为它是无效的初始化。即使这样行得通,我也很难级联cat的另一个数组段。
1 2 3 4 5 6
90 91 92 93 94 95
0
第一行显示被调用6次的狗ID,第二行显示被调用6次的cat ID。
(*test-7)->get_ID();
是最后一个数字。
animal** myArray;
{do something}
cout << myArray[2].get_name() << endl << myArray[7].get_ID();
它输出
Woof! Corgi
91
最佳答案
关于animal
类的一个重要细节:多态类型在调用其析构函数时会遇到问题,但那些析构函数不是virtual
。即使基类本身实际上不需要析构函数,也建议您将基类的析构函数设为虚拟。在这种情况下,您可以告诉编译器您希望析构函数为virtual
,但使用以下方法生成它的默认实现:
virtual ~animal() = default;
在
public:
类的
animal
部分中添加以上行。这样可以确保您以后定义的所有派生类将自动获得虚拟析构函数。
p = new dog;
到现在为止还挺好。但是然后这样:
p++;
除了使指针指向无效地址外,没有任何其他帮助。然后在下一次迭代中,将执行另一个
p = new dog;
。您分配的上一个
dog
对象现在将永远丢失。您遇到了所谓的“泄漏”。
new
分配对象的一种方式可以将它们一个接一个地放置在内存中。事实并非如此。
new
将在不可预测的位置分配内存。结果,这:
*test-7
由于对象未按预期方式放置在内存中,因此无法正常工作。相反,您得到的是到最近分配的对象之前7个“位置”的某个内存位置的地址,该地址肯定不会指向您希望的
animal
对象。当您以后取消引用时,您将获得未定义的行为。一旦发生这种情况,您就无法再对结果进行推理了。从看到打印错误的文本到程序崩溃,它们可以是任何东西。
animal
指针数组,则应专门创建一个:
animal* animals[12];
这将创建一个名为
animals
的数组,其中包含12个
animal
指针。然后可以初始化这些指针:
for (int i = 0; i < 6; i++) {
animals[i] = new dog;
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = new cat;
}
然后,只需指定要访问的数组的索引即可:
cout << animals[0]->get_ID() << '\n'; // first animal
cout << animals[6]->get_ID() << '\n'; // seventh animal
完成数组操作后,不要忘记删除对象。由于
animals
是一个数组,因此可以使用ranged循环删除其中的所有对象:
for (auto* animal_obj : animals) {
delete animal_obj;
}
但是,所有这些低级代码都很繁琐且容易出错。建议改用库工具为您完成分配和清理工作,例如
std::unique_ptr
。第一步,您可以将原始
animal*
指针替换为
std::unique_ptr<animal>
:
unique_ptr<animal> animals[12];
(不要忘记在源文件中添加
#include <memory>
,因为
std::unique_ptr
由该库头提供。)
for (int i = 0; i < 6; i++) {
animals[i] = make_unique<dog>();
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = make_unique<cat>();
}
现在,您不需要
delete
任何东西。一旦超出范围,智能指针将自动为您执行此操作(在这种情况下,这意味着
animals
数组超出范围,这在
main()
函数退出时发生)。
animals
数组替换为
std::vector
或
std::array
。选择哪一个取决于您是否希望阵列以后能够增长或缩小。如果只需要数组中的12个对象,则
std::array
将执行以下操作:
array<unique_ptr<animal>, 12> animals;
(您需要
#include <array>
。)
for
循环保持不变。
std::array
比纯数组(也称为“内置数组”)更好,因为它提供了
.size()
成员函数,该函数告诉您数组可以容纳的元素数量。因此,您不必手动跟踪数字12。同样,当您将
std::array
传递给以
animal*
作为参数的函数时,它不会像普通数组那样衰减到指针。这样可以防止一些常见的编码错误。如果您想从
animal*
实际获取
std::array
指针,则可以使用其
.data()
成员函数,该函数返回指向数组第一个元素的指针。
std::vector
代替:
vector<unique_ptr<animal>> animals;
(您需要
#include <vector>
。)
unique_ptr<animal>
类型的元素。要实际向其中添加元素,请使用
.push_back()
的
std::vector
函数:
// Add 6 dogs.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<dog>());
}
// Add 6 cats.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<cat>());
}
可以使用
push_back()
代替
emplace_back()
进行优化,但是在这种情况下,它并不重要。他们要记住的关键点是,一旦将元素推入 vector , vector 就会自动增长。它会自动执行此操作,而无需您手动分配新元素。这使得编写代码更加容易,并且不易出错。
main()
返回), vector 将自动删除为其分配的用于存储元素的内存,并且由于这些元素是智能指针,因此它们又将自动删除其指向的
animal
对象。 。
关于c++ - 难以理解c++多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64548052/
我来自 Asp.Net 世界,试图理解 Angular State 的含义。 什么是 Angular 状态?它类似于Asp.Net中的ascx组件吗?是子页面吗?它类似于工作流程状态吗? 我听到很多人
我一直在寻找 3 态拨动开关,但运气不佳。 基本上我需要一个具有以下状态的开关: |开 |不适用 |关 | slider 默认从中间开始,一旦用户向左或向右滑动,就无法回到N/A(未回答)状态。 有人
我是一名优秀的程序员,十分优秀!