Хранение объектов различных производных классов абстрактного базового класса в массиве в C ++ - PullRequest
0 голосов
/ 10 марта 2019

Я - полный новичок, пытающийся изучать C ++. Так что этот вопрос может звучать очень клише ». Пожалуйста, помогите мне понять, где я иду не так.

Проблема описана ниже.

Цель:

  1. Определите абстрактный класс Shape, который будет действовать как интерфейс. (Используйте чисто виртуальные функции)
  2. Переопределить методы в производных классах Rectangle, Circle, Triangle.
  3. Требуются две функции - а. read () -> Чтобы прочитать входные параметры (измерения) определенной формы. б. area () -> Для расчета общей площади фигуры.
  4. Хранить объекты (или указатели на объекты) различных производных классов в массиве.
  5. Рассчитать площадь каждого элемента массива.
  6. Рассчитать общую площадь.

Фрагменты кода:

shape.hpp - Заголовочный файл базового класса.

namespace generalShape
{
 class Shape { 
     public :          
         virtual void read() = 0;
         virtual double area() = 0 ;         
 };
}

rect.hpp - Заголовочный файл производного класса.

namespace rect2D
{
 class Rectangle {
     private :
         double length;
         double breadth;

     public :
         void read();
         double area() ;           
 };
}

Подобные заголовочные файлы также написаны для двух других производных классов, а именно circle.hpp и triangle.hpp

rect.cpp - Файл реализации производного класса.

using namespace rect2D;

// Read data (use it in main.cpp)
void Rectangle::read(/* no args */)
{   
 std::cin >>  length;  
 std::cin >>  breadth;
}

// To calculate area of a rectangle object
double Rectangle::area(/* no args */)
{ 
 return length * breadth;   
}

Подобные файлы реализации также написаны для двух других производных классов, а именно circle.cpp и triangle.cpp

main.cpp - файл клиента.

using namespace generalShape;
using namespace rect2D;
// similarly use other namespaces as required

int main()
{
 int number_of_shapes; // take input from user about number of objects
 double total_area = 0;

 /* Method 1 */
 Shape **arr;
 arr = new Shape*[size];

 /* Method 2 */
 //vector<Shape *> arr;

 for (int i = 0; i < number_of_shapes; i++)
 {
     // some code to ask user about type of object

     if (choice == 1)//based on user input
     {
         arr[i] = new Rectangle();       // for method 1
         //arr.push_back(new Rectangle); // for method 2
     }

     // similar code for other derived class object types

     // Code to calculate total_area of all objects in array.
     arr[i]->read();
     total_area += arr[i]->area();
 }
 return 0;
}

В чем моя проблема?

В main.cpp я указал Метод 1 и Метод 2 в качестве строк комментариев в основной функции.

Метод 1 пытается использовать массив указателей базового класса для указания на объекты производного класса различных классов (это разрешено, верно?). Но это дает ошибку. error: cannot convert ‘rect2D::Rectangle*’ to ‘generalShape::Shape*’ in assignment и аналогичные ошибки для других объектов производного класса.

Итак, я попытался определить тип решения проблемы.

// Shape is the base class with virtual methods read() and area().
// Rectangle,Triangle,Circle are derived classes which override these methods.
// main.cpp uses these header files to read user input using read() for each 
// derived class and then calculate area using area(). The ultimate goal is to 
// calculate total area of all derived class objects stored in an array.

arr[i] = (Shape*)(new Rectangle()) ;

Это позволяет выполнить компиляцию без ошибок. Но когда я пытаюсь выполнить, это дает ошибку сегментации. Я не уверен, почему это происходит. Но я думаю, это потому, что я определил чисто виртуальные функции в заголовочном файле базового класса. Даже если это так, я не уверен, как это исправить.

Во-вторых, в Методе 2 я пытался использовать векторов для достижения аналогичной функциональности после просмотра других предложений по stackoverflow. Но сейчас я получаю сообщение об ошибке.

error: no matching function for call to ‘std::vector<generalShape::Shape*>::push_back(rect2D::Rectangle*)’
             arr.push_back(new Rectangle);
                                        ^
In file included from /usr/include/c++/7/vector:64:0,
                 from src/main.cpp:2:
/usr/include/c++/7/bits/stl_vector.h:939:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = generalShape::Shape*;
_Alloc = std::allocator<generalShape::Shape*>; std::vector<_Tp, _Alloc>::value_type = generalShape::Shape*]
       push_back(const value_type& __x)
       ^~~~~~~~~
/usr/include/c++/7/bits/stl_vector.h:939:7: note:   no known conversion for argument 1 from ‘rect2D::Rectangle*’ to ‘generalShape::Shape* const&’
/usr/include/c++/7/bits/stl_vector.h:953:7: note: candidate: void std::vector<_Tp, _Alloc>::push_back(std::vector<_Tp, _Alloc>::value_type&&) [with _Tp = generalShape::Shape*; _Alloc = std::allocator<generalShape::Shape*>; std::vector<_Tp, _Alloc>::value_type = generalShape::Shape*]
       push_back(value_type&& __x)
       ^~~~~~~~~

И я не могу понять, как это исправить. Итак, я застрял в этой проблеме и не могу ее решить. Пожалуйста, помогите мне разобраться и исправить ошибки.

1 Ответ

1 голос
/ 10 марта 2019

вы просто забыли указать, что ваш класс rect2D :: Rectangle реализует ваш абстрактный интерфейс класса generalShape :: Shape.

Вы можете сделать это, добавив

: public generalShape :: Shape

к объявлению rect2D :: Rectangle. Фиксированная декларация тогда:

namespace rect2D
{
 class Rectangle : public generalShape::Shape {
     private :
         double length;
         double breadth;

     public :
         void read();
         double area() ;
 };
}

Еще один совет: определите виртуальный деструктор в вашем базовом классе generalShape :: Shape, если вы собираетесь уничтожать ваши объекты через контейнер, содержащий указатели на базовый класс.

...