向数组中添加类

Adding Classes to an Array

本文关键字:添加 数组      更新时间:2023-10-16

我正在做一项关于使用OOP查找不同形状数组的大学作业。我已经创建了我所有的形状类,所以它们派生自我的主形状类。形状类被用作接口,因此从形状类派生的所有形状类都必须具有计算面积函数等。我想创建一个不同形状的数组。我已经声明了一个具有形状类型的数组,它是父类,我想将每个不同形状、圆形、方形、矩形和三角形的新实例添加到数组列表中,以便将每个形状的所有信息存储在一个数组中。我有下面的代码,但我在aShapes[I]=square这行有一个错误说形状是正方形难以接近的基础。

如果有人能帮忙,那就太好了。

提前感谢。

这是我的代码

#include <cstdlib>
#include <iostream>
#define M_PI 3.14159265358979323846
using namespace std;
class Shape{    
public:
string sName;
float nArea;
void fnAddData();
float fnCalculateArea();     
};
class Square : private Shape {
private:
float nSide;   
void fnAddData()
{
cout << "Please enter the length of a side: ";
cin >> nSide;
}
float fnCalculateArea(float side)
{
return (side * side);
}  
public:
Square()
{
sName = "Square";
fnAddData();
nArea = fnCalculateArea(nSide);
}        
};
Shape aShapes[5];

/*
* 
*/
int main(int argc, char** argv) 
{
int decision;    
Square square;
for (int i = 0; i < 5; i++)
{
cout << "Shape number";
cin >> decision;
switch (decision)
{
case 1:
aShapes[i] = square;
}                        
}    
return 0;
}

数组不是多态的:存储在数组中的所有内容都必须是相同的类型。你的Shape数组不起作用1

那么,在使用数组时,如何获得多态性呢?更改数组以存储指向Shape:的指针

Shape *aShapes[5];

这很好地解决了这个问题:Shape*可以指向Shape或其任何子代2,并且所有Shape*本身都是相同的类型。

然后在主代码中,存储数组中对象的地址:

aShapes[i] = &square;

您需要对现有代码进行一些其他更改才能使其工作:

  • 使用公共继承,而不是私有传承
  • 使Shape中的方法虚拟化
  • 使Square中重写Shape定义的接口的方法为public
  • 添加一个虚拟析构函数

1如果成功地将Shape的后代复制到数组中,则最终会对对象进行切片

2技术性:如果给Shape提供纯虚拟方法,则无法创建纯Shape的实例。在这种情况下,Shape*不能指向Shape的实例,因为您无法创建一个实例!Shape*将仅指向其实现所有虚拟方法的子代之一

出现该错误的原因是,您使用的是private继承,而实际上您确实希望使用public继承。

class Square : public Shape {
^^^^^^

另一个问题是多态性只适用于指针或引用。不能将Square放入Shapes的数组中。它将简单地切出SquareShape部分,并将其放入阵列中。Shape aShapes[5];只不过是Shapes的数组——没有Squares,没有Triangles,只有Shapes。你需要的是这样的东西:

Shape* aShapes[5];

然后,您可以将此数组中的指针设置为指向从Shape派生的类型的对象。

您还需要制作要在派生类virtual中重写的函数。当编译器看到类似aShapes[0]->fnCalculateArea()的东西,然后看到fnCalculateArea是一个虚拟函数时,它只会查找aShapes[0]指向的对象的动态类型——然后它会看到它是一个Square并调用Square::fnCalculateArea

1)您私下继承了Shape,这通常是一种不受欢迎的合成形式。出于您的目的,您应该公开继承Shape。

class Square : public Shape

2) Shape的任何成员函数都没有声明为虚拟的,因此它们都不会被派生类覆盖。您也没有虚拟析构函数。如果要在指向正方形的Shape指针上调用Square的CalculateArea函数,则必须在Shape中声明为虚拟,并在Square:中覆盖它

形状:

virtual float fnCalculateArea();

方形:

void float fnCalculateArea() override;

3) 如果Shape应该只作为一个抽象接口,而不是实例化它自己,那么你应该通过使它的一个函数纯虚拟(如果没有其他函数的话,至少是析构函数)来实现它。

virtual ~Shape() = 0 {}

4) 如果你想将不同的派生类型存储在一个容器中,那么你必须通过引用来存储它们,IE通过指向它们基类的指针来存储它们。

Shape* aShapes[5];

5) 我还注意到,您在许多变量名前面加了n,尽管它们是浮点值。匈牙利表示法通常使用n表示int,使用f表示float。

值数组的行为不具有多态性。您将不得不使用一个指向Shape的指针数组,因为对指针的访问和赋值确实具有多态性。

这里的方法是对象切片,即剪切Derived类块,使对象适合Base。这太糟糕了。

然而,有了指针,就不会得到切片。

您的特定错误源于使用私有继承,它禁止转换到继承的类。使用公共继承。这只是掩盖了上述问题。