【问题标题】:Polymorphism and defining a list of different objects in C++多态性和在 C++ 中定义不同对象的列表
【发布时间】:2020-02-01 06:18:59
【问题描述】:

为什么我的代码返回错误?我定义了一个名为 Shape 的父类和两个派生类。我正在尝试存储由类定义的对象并将它们存储在列表中。

# include <iostream>

using namespace std;

class Shape{
    public:
        virtual double area(const double &height, const double &weight) const = 0;
};

class Triangle: public Shape{
   public:
       double height, weight;
       Triangle(double height, double weight): height(height), weight(weight){}
   double area(){
       return (height*weight)/2;
   }
};

class Rectangle: public Shape{
    public:
        double height, weight;
        Rectangle(double height, double weight): height(height), weight(weight){}
    double area(){
        return height*weight;
    }
};

Shape *shapes[3];
shapes[0] = new Triangle(2, 1);
shapes[1] = new Rectangle(3, 2);
shapes[2] = new Rectangle(5, 2);

double * show(Shape *shapes){
    double arr[3];
    for (int i=0; i < 3; i++){
        arr[i] = shapes[i].area();
    }
    return arr;
}

int main(){
    double arr[3] = show(shapes);
    cout << arr[0] << endl;
    cout << arr[1] << endl;
    cout << arr[2] << endl;
}

但我收到这两个错误:

错误:“形状”没有命名类型 形状[0] = 新三角形(2,1);

错误:无法将 'shape**' 转换为 'shape*' 双 arr[3] = 显示(形状);

【问题讨论】:

  • shapes[0] = new Triangle(2, 1); 等 - 您不能在全局范围内拥有代码。将这些语句移到 main() 中。
  • 另外,show() 返回一个指向局部变量的指针。那是UB。
  • 除了 Sid S 的回复,您的 Shape* shapes[3]; 定义了一个大小为 3 的 Shape* 类型的数组。数组的名称是指向第一个元素的指针(这里不讨论衰减),所以shapes 的类型为Shape**。你的shapes[i].area() 应该是shapes[i]-&gt;area()。您的纯虚函数 area() 未在派生类中正确覆盖。
  • @Sid S。我已经按照你说的做了,但我收到了这个错误:抽象类类型“三角形”的新表达式无效。
  • @szppeter - 对不起,那是错误的。数组的名称不是指针。数组的名称可以在某些上下文中使用它是指针,在某些上下文中隐式转换为指针(有些人称之为“衰减”),但它不是指针.当然,Shape * 数组和Shape ** 数组完全不同。

标签: c++


【解决方案1】:

你的代码有几个问题:

  1. 您的抽象基类Shape 有一个纯虚函数area(),它接受参数,但您的派生类不接受。所以它也使你的派生类abstract,所以你不能初始化派生类对象。
  2. 您不能声明一个指针数组Shapes* shapes[3];,然后在全局范围内单独分配它们。这是您遇到的第一个错误。更完整的解释见here
  3. 当您调用show(shapes) 函数时,shapesShapes* 数组的名称,它衰减为指向第一个元素的指针。结果类型应该是Shapes**,这是您遇到的第二个错误。
  4. 你在show()函数中的shapes[i]是一个指向对象的指针,所以你应该使用-&gt;而不是.
  5. 你的double arr[3];是栈上的一个数组,所以函数执行完返回后,内容就被销毁了。返回指向被破坏元素的指针是未定义的。
  6. 你没有deletenew创建的所有对象,导致内存泄漏。

要使您的代码正常工作,最少需要进行以下更改:

# include <iostream>

using namespace std;

class Shape {
public:
    virtual double area() const = 0;
};

class Triangle : public Shape {
public:
    double height, weight;
    Triangle(double height, double weight) : height(height), weight(weight) {}
    double area() const override {    //add override to let compiler check for correctness
        return (height * weight) / 2;
    }
};

class Rectangle : public Shape {
public:
    double height, weight;
    Rectangle(double height, double weight) : height(height), weight(weight) {}
    double area()const override {
        return height * weight;
    }
};

Shape* shapes[3] = { new Triangle(2, 1),  new Rectangle(3, 2) ,new Rectangle(5, 2) };

double* show(Shape** shapes) {
    double* arr = new double[3];
    for (int i = 0; i < 3; i++) {
        arr[i] = shapes[i]->area();
        delete shapes[i];    //free the object pointed in shapes[]
    }
    return arr;
}

int main() {
    double* arr = show(shapes);
    cout << arr[0] << endl;
    cout << arr[1] << endl;
    cout << arr[2] << endl;
    delete[] arr;
}

但是有一些建议需要改进,比如在堆栈上创建对象而不使用new而不是堆,以及使用std::array创建数组等。

【讨论】:

  • 我应该使用什么版本的 C++?
  • @bitWise override 关键字是在 C++11 中引入的,但您可以将其移除(!强烈不推荐!)以使其与 C++98 兼容,最古老的标准。如果可以使用新标准,则此功能代码非常“糟糕”。
猜你喜欢
  • 2015-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-04
相关资源
最近更新 更多