2013-12-20 2 views
0

Я работаю над университетским заданием о поиске массива различных форм с использованием ООП. Я создал все мои классы форм, поэтому они происходят из моего основного класса формы. Класс Shape используется как интерфейс, так что все классы формы, полученные из класса формы, должны иметь функцию области расчета и т. Д. Я хочу создать массив разных форм. Я объявил массив с типом формы, который является родительским классом, и я хочу добавить новые экземпляры каждой формы, круга, квадрата, прямоугольника и треугольника в список массивов, чтобы вся информация о каждой форме хранилась в один массив. У меня есть следующий код, но у меня есть ошибка в строке 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; 
} 
+0

Вы подвергаетесь разрезанию объектов. – chris

+0

'class Square: private Shape' - почему [частное наследство] (http://stackoverflow.com/questions/1576978/private-inheritance) здесь? –

+0

Вы также хотите предоставить 'Shape' виртуальный деструктор. – chris

ответ

3

Массивы не полиморфный: Все хранится в массиве должны быть одного типа. Ваш массив Shape не будет работать.

Так как же вы получаете полиморфизм при использовании массива? Измените массив для хранения указателей в Shape:

Shape *aShapes[5]; 

Это решает проблему красиво: A Shape* может указывать на Shape or any of its descendants, и все сами Shape* того же типа.

А потом в основной код, хранить адреса объектов в массиве:

aShapes[i] = &square; 

Вам нужно будет сделать несколько других изменений в существующий код, чтобы сделать эту работу:

  • Использование public inheritance, not private inheritance.
  • Сделать методы в Shape виртуальных.
  • Внесите методы в Square, которые переопределяют интерфейс, определенный Shapeобщественный.
  • Добавить virtual destructor.

Если вы сделать удается скопировать потомка Shape в массив, вы в конечном итоге slicing the object.

Формальности: Если вы даете Shapepure virtual методы, вы не сможете создать экземпляр чистого Shape. В этом случае Shape* не может указывать на экземпляр Shape, потому что вы не можете создать его!A Shape* будет указывать только на один из его потомков, который реализует все виртуальные методы.

+0

спасибо за помощь. :) – CraigWake

1

Причина, по которой вы получаете эту конкретную ошибку, заключается в том, что вы используете наследование private, когда похоже, что вы действительно хотите использовать public наследование.

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

Еще одна проблема заключается в том, что полиморфизм работает только с указателями или ссылками. Вы не можете поместить Square в массив Shapes. Он просто отрежет Shape часть Square и поместит его в массив. Shape aShapes[5]; - это не что иное, как массив Shapes - нет Squares, нет Triangles, всего Shapes. Что вам нужно, это что-то вроде:

Shape* aShapes[5]; 

Вы можете установить указатели в этом массиве, чтобы указать на объектах типов, которые вытекают из Shape.

Вам также необходимо будет выполнить функции, которые вы хотите переопределить в производных классах virtual. Когда компилятор видит что-то вроде aShapes[0]->fnCalculateArea(), а затем видит, что fnCalculateArea - это виртуальная функция, он только тогда будет искать динамический тип объекта, на который указывает aShapes[0], - тогда он увидит, что это Square и звоните Square::fnCalculateArea.

+0

Блестящий, спасибо за вашу помощь. – CraigWake

+0

как вы указываете на конструктор. Я никогда раньше не использовал указатели, они меня немного смутили. В моем конструкторе я вызываю fnCalculateArea и т. Д., Поэтому я просто хочу, чтобы конструктор произошел – CraigWake

+0

Если ваши фигуры еще не статически выделены, вы можете динамически их распределить: 'aShapes [i] = new Square;' В этом случае вы должны не забудьте освободить его, когда вы закончите с ним: 'delete aShapes [i];' – derpface

0

Массивы значений НЕ ведут себя полиморфно. Вам нужно будет использовать массив указателей для Shape, поскольку доступ и назначение указателей ведут себя полиморфно.

Что вы имеете здесь, нарезание объектов, вы отрезаете кусок Derived класса, чтобы ваш объект вписывался в базу. Это плохо.

С указателем, однако, вы не получаете нарезки.

Ваша конкретная ошибка связана с использованием частного наследования, которое запрещает преобразование в унаследованный класс. Использовать публичное наследование. Это просто маскирует проблему выше.

1

1) Вы частно наследуете от Shape, что более типично является нежелательной формой композиции. Вы должны публично наследовать от Shape для своих целей.

class Square : public Shape 

2) Ни одна из функций члена Shape не объявлена ​​виртуальной, поэтому ни один из них не будет переопределен производными классами. У вас также нет виртуального деструктора. Если вы хотите, чтобы функция CalculateArea от площади, которые будут использоваться при вызове его на указатель Shape, который указывает на площади, вы должны объявить как виртуальный в форму, и заменить его на площади:

В Форма:

virtual float fnCalculateArea(); 

в площадь:

void float fnCalculateArea() override; 

3) Если форма должна действовать только в качестве абстрактного интерфейса, а не быть создан сам по себе, то вы должны сделать так, делая одну из его функций чисто виртуальный (деструктор в наименее, если ничего другого).

virtual ~Shape() = 0 {} 

4) Если вы хотите сохранить различные производные типы в одном контейнере, то вы должны хранить их по ссылке, IE через указатель на их базовый класс.

Shape* aShapes[5]; 

5) Я также заметил, что вы предваряя многие имена переменных n, даже если они являются поплавки. Венгерская нотация обычно использует n для обращения к ints и f для обозначения плавающих.

+0

, если я сделаю fnCalculateArea в форме виртуальной и переопределяю ее в квадрате, она дает мне функцию члена ошибки, объявленную с помощью переопределение не переопределяет, не переопределяет элемент базового класса. Есть идеи? Спасибо – CraigWake

+0

Если вы получили эту ошибку, это значит, что что-то в квадрате не соответствует объявлению в Shape. В исходном коде версия Square использует float, а Shape - нет. В вашем квадратном классе есть член данных 'nSide', и функция вашего квадрата принимает аргумент' side'. Кого вы намеревались использовать? Я бы предположил, что вы хотите использовать элемент данных 'nSide', но решите это, затем сделайте обе версии функции совпадающими. – derpface

+0

Я делаю это, потому что у меня есть другие формы, включая круг, прямоугольник и треугольник, поэтому каждый из них использует разные параметры для обработки области, поэтому я не хочу принимать переменную в классе формы. Я хочу, чтобы у меня были перегрузки. Я не уверен, могу ли я это сделать или нет? – CraigWake

Смежные вопросы