Не могу объявить массив указателей на класс, который наследуется об абстрактного класса
![<code></p>
<p>При объявление массива указателей на это класс не могу присвоить им значения.вот скрин ошибок(работаю в xcode 8</code>» /></p>
<p>Отслеживать<br />
Gleb Nazemnov<br />
задан 20 мая 2017 в 17:32<br />
Gleb Nazemnov Gleb Nazemnov<br />
111 1 1 золотой знак 1 1 серебряный знак 9 9 бронзовых знаков</p>
<p>Так «не могу объявить», или «объявить могу, но не могу присвоить значения»? Почему в заголовке написано одно, а в тексте — совсем другое?</p>
<p>20 мая 2017 в 17:58</p>
<h3>2 ответа 2</h3>
<p>Сортировка: Сброс на вариант по умолчанию</p>
<p>Ваши классы-наследники реализуют не все чисто-виртуальные методы. Они либо должны реализовывать makeARezalt(), либо он должен быть просто виртуальным, либо вообще не виртуальным. Кстати, вы забыли про виртуальный деструктор в базовом классе и в наследниках, без него ваши объекты гарантированно будут неправильно удалены.</p>
<p>И если уж вы пишете на c++, используете std::vector> для массива указателей.</p>
<p>Edit: Вот вариант решения. Для std::make_unique нужен c++14, но можно создавать объекты просто через new.</p>
<pre><code>#include #include #include #include #include #include class UnaryFunction < public : virtual void show() const = 0; virtual double calcValue(double x) const = 0; virtual ~UnaryFunction() = default; >; class LineFunction : public UnaryFunction < double a, b; public : LineFunction(): a(0), b(0) <>LineFunction(double a, double b): a(a), b(b) <> void show() const override < std::coutdouble calcValue(double x) const override < return a*x+b; >~LineFunction() override = default; >; class CubeFunction : public UnaryFunction < double a, b,c; public : CubeFunction(): a(0), b(0), c(0) <>CubeFunction(double a, double b, double c): a(a), b(b), c(c) <> void show() const override < std::cout double calcValue(double x) const override < return a*x*x+b*x+c; >~CubeFunction() override = default; >; class HyperbolaFunction : public UnaryFunction < double a; public : HyperbolaFunction(): a(0) <>HyperbolaFunction(double a): a(a) <> void show() const override < std::coutdouble calcValue(double x) const override < if(x!=0)< return a/x; >else< throw std::invalid_argument; > > ~HyperbolaFunction() = default; >; int main(int argc, const char * argv[]) < volatile double x = 12; std::vector> functions; functions.push_back(std::make_unique(1, 2)); functions.push_back(std::make_unique(3)); functions.push_back(std::make_unique(15, 2, 4)); functions.push_back(std::make_unique(18, 12)); try< for(auto&& function: functions)< function->show(); std::cout f(x) mt24](https://i.stack.imgur.com/m6pzP.png)
![<code></p>
<p>При объявление массива указателей на это класс не могу присвоить им значения.вот скрин ошибок(работаю в xcode 8</code>» /></p>
<p>Отслеживать<br />
Gleb Nazemnov<br />
задан 20 мая 2017 в 17:32<br />
Gleb Nazemnov Gleb Nazemnov<br />
111 1 1 золотой знак 1 1 серебряный знак 9 9 бронзовых знаков</p>
<p>Так «не могу объявить», или «объявить могу, но не могу присвоить значения»? Почему в заголовке написано одно, а в тексте — совсем другое?</p>
<p>20 мая 2017 в 17:58</p>
<h3>2 ответа 2</h3>
<p>Сортировка: Сброс на вариант по умолчанию</p>
<p>Ваши классы-наследники реализуют не все чисто-виртуальные методы. Они либо должны реализовывать makeARezalt(), либо он должен быть просто виртуальным, либо вообще не виртуальным. Кстати, вы забыли про виртуальный деструктор в базовом классе и в наследниках, без него ваши объекты гарантированно будут неправильно удалены.</p>
<p>И если уж вы пишете на c++, используете std::vector> для массива указателей.</p>
<p>Edit: Вот вариант решения. Для std::make_unique нужен c++14, но можно создавать объекты просто через new.</p>
<pre><code>#include #include #include #include #include #include class UnaryFunction < public : virtual void show() const = 0; virtual double calcValue(double x) const = 0; virtual ~UnaryFunction() = default; >; class LineFunction : public UnaryFunction < double a, b; public : LineFunction(): a(0), b(0) <>LineFunction(double a, double b): a(a), b(b) <> void show() const override < std::coutdouble calcValue(double x) const override < return a*x+b; >~LineFunction() override = default; >; class CubeFunction : public UnaryFunction < double a, b,c; public : CubeFunction(): a(0), b(0), c(0) <>CubeFunction(double a, double b, double c): a(a), b(b), c(c) <> void show() const override < std::cout double calcValue(double x) const override < return a*x*x+b*x+c; >~CubeFunction() override = default; >; class HyperbolaFunction : public UnaryFunction < double a; public : HyperbolaFunction(): a(0) <>HyperbolaFunction(double a): a(a) <> void show() const override < std::coutdouble calcValue(double x) const override < if(x!=0)< return a/x; >else< throw std::invalid_argument; > > ~HyperbolaFunction() = default; >; int main(int argc, const char * argv[]) < volatile double x = 12; std::vector> functions; functions.push_back(std::make_unique(1, 2)); functions.push_back(std::make_unique(3)); functions.push_back(std::make_unique(15, 2, 4)); functions.push_back(std::make_unique(18, 12)); try< for(auto&& function: functions)< function->show(); std::cout f(x) mt24](https://i.stack.imgur.com/m6pzP.png)
Ваши классы остаются абстрактными, ибо вы не реализуете чисто виртуальные функции:
class Function < public : virtual void Show() = 0; virtual double Value() = 0; >;
У вас нет реализаций double Value(); , вы передаете в них параметры - значит, сигнатуры разные, так что.
Я бы на вашем месте делал
class Function < public : virtual double Value(double x) const = 0; virtual ~Function()<>>;
Ну, а наследники должны реализовывать соответствующую функцию, типа
class Cube : public Function < double a, b,c; public: Cube(double a = 0.0, double b = 0.0, double c = 0.0): a(a), b(b), c(c) <>double Value(double x) const < return (a*x+b)*x+c; >~Cube()<> >;
Ну вот на фига вы передавали в Value() значения a , b и c . Если вы их храните в классе?
Есть казалось бы простое учебное задание для C++: реализовать классы связанного списка, динамического массива и статического массива. Все три класса должны быть наследниками одного абстрактного класса.
Вроде бы понятно, что может быть общего у динамического массива, там указатель на первый элемент, метод доступа по индексу.
А вот реализация статического массива вообще как-то не вяжется с остальными. На сколько эта часть задания соответствует здравому смыслу и реальным задачам? На мой не опытный взгляд уже есть обычный встроенный массив и в реализации динамического массива его следует использовать как поле данных. Как реализовать свой статический массив я не представляю.
1 комментарий
Оценить 1 комментарий

Сравните std::vector и std::array
Решения вопроса 1
Живу в своё удовольствие
В вашем случае в базовом классе должен быть указатель на первый элемент, метод для доступа по индексу и метод для получения количества элементов в массиве. Возможно, в ходе выполнения что-то еще выделите у них общего.
Для реализации статического массива в конструкторе выделяйте память на нужное количество элементов, а при доступе по индексу - просто делайте смещение от указателя на первый элемент - вот вам и реализация стандартного массива
Ответ написан более трёх лет назад
Комментировать
Нравится Комментировать
Ответы на вопрос 2
Full-stack developer (Symfony, Angular)
вы можете организовать одинаковый интерфейс для связанного списка и статического массива? Можете. Вот и весь ответ.
В этом случае остальной код будет завязан именно на абстрактный класс, описывающий интерфейс, а уже какую реализацию вы подсуните - разницы не имеет. Это называется полиморфизм подтипов.
Ответ написан более трёх лет назад
vipermagi @vipermagi Автор вопроса
Вы намекаете, что реализация пользовательского статического массива это просто обёртка над встроенным статическим массивом?
vipermagi: не обертка, а своя реализация должна быть. Такими темпами под каждый из трех классов можно стандартный подсунуть, что в пределах лабораторной работы не требуется
vipermagi: ну у вас же будет операция вставки в середину списка например? Со статическим массивом вам нужно будет хэндлить ресайзы и т.д. Интерфейс один, реализация разная.
Программист на «си с крестами» и не только
Вариант один вы предложили. Всё пишу на C++03, без шаблонов. C++11 и шаблоны, разумеется, дадут больше вариантов.
class Object < public: virtual ~Object() <>>; class List < // interface protected: virtual Object& getAt(size_t i) = 0; public: virtual size_t size() const = 0; inline Object& at(size_t i) < return getAt(i); >inline const Object& at(size_t i) const < return const_cast(this)->getAt(i); > virtual ~List() <> >;
Вариант 2. С ним пользователю не так просто, но если к нему ещё добавить лямбда-функции C++11 — вообще бомба будет!
class ListCallback < // interface public: virtual void act(size_t index, Object& object) = 0; virtual ~ListCallback() <>>; class ListConstCallback < // interface public: virtual void act(size_t index, const Object& object) = 0; virtual ~ListConstCallback() <>>; class List2 < // interface public: virtual size_t size() const = 0; virtual void enumerate(ListCallback& body) = 0; virtual void enumerate(ListConstCallback& body) const = 0; >;
Например, для динамического массива, у которого быстрый доступ по номеру, будет такое тело
void DynArray::enumerate(ListConstCallback& body) const
Разумеется, если вы нагрузкой сделаете не абстрактный Object, а что-то окончательное, dynamic_cast не нужен будет.
Вариант 3 принят в Java. Один недостаток — мого кода писать для const-корректности, так что с вашего позволения опущу.
class VirtualListIterator < // interface public: virtual bool next() = 0; virtual Object& value() = 0; virtual ~VirtualListIterator() <>>; class ListIterator < // Назван так для красоты, по сути это умный указатель private: VirtualListIterator* ptr; // Запретим копирование и op=, но при желании можно реализовать и их ListIterator(ListIterator&) <>void operator=(const ListIterator&) <> public: ListIterator() : ptr(NULL) <> ListIterator(VirtualListIterator* value) : ptr(value) <> ~ListIterator() < delete ptr; >bool next() < return ptr->next(); > Object* operator->() const < return &ptr->value(); > Object& operator*() const < return ptr->value(); > >; class List3 < // interface public: virtual size_t size() const = 0; virtual VirtualListIterator* enumerate() = 0; >; class Number : public Object < public: int value; >; // И пользоваться этим так. void doSmth(List3& aList) < ListIterator it(aList.enumerate()); while (it.next()) < std::cout (*it).value >
Во всех трёх вариантах не забывайте: если нагрузка — не что-то окончательное, а абстрактный класс, элементы придётся хранить по указателю и вручную уничтожать.
Да, и из вас будет хороший инженер, если вы сразу же задумываетесь о производительности.
Абстрактные методы – это методы у которых отсутствует реализация.
аbstract тип имяМетода(списокПараметоров);
public abstract double calculateArea();
Абстрактные методы должны быть обязательно переопределены в подклассе.
Любой класс, содержащий один или больше абстрактных методов, должен быть также объявлен как абстрактный. Для этого достаточно указать ключевое слово abstract перед ключевым словом class в начале объявления класса:
public abstract class Figure2
У абстрактного класса в Java не может быть никаких объектов. Но абстрактные классы можно применять для создания ссылок на объекты. Например:
public abstract class Figure2 < . public abstract double calculateArea(); public static void main(String[] args) < // У абстрактного класса не может быть никаких объектов. // Figure2 figure1 = new Figure2(); // Но абстрактные классы можно применять для создания ссылок на объекты. Figure2 figure2 = new Rectangle(); >>
Также нельзя объявлять абстрактные конструкторы или абстрактные статические методы.
Рассмотрим пример использования абстрактных классов и методов на примере класса Figure и его наследников Triangle и Rectangle , которые мы рассматривали в Переопределение методов. Класс Figure описывает абстрактную фигуру, для которой вычисление площади не имеет смысла, поэтому метод calculateArea() более правильно сделать абстрактным.

public abstract class Figure2 < double dimension1; double dimension2; public Figure2(double dimension1, double dimension2) < this.dimension1 = dimension1; this.dimension2 = dimension2; >public abstract double calculateArea(); >
Любой подкласс, производный от абстрактного класса, должен реализовать все абстрактные методы из своего супер класса или же сам быть объявлен абстрактным:
public class Rectangle2 extends Figure2 < public Rectangle2(double dimension1, double dimension2) < super(dimension1, dimension2); >public double calculateArea() < System.out.println("B области четырехугольника."); return dimension1 * dimension2; >>
public class Triangle2 extends Figure2 < public Triangle2(double dimension1, double dimension2) < super(dimension1, dimension2); >public double calculateArea() < System.out.println("B области треугольника."); return dimension1 * dimension2 / 2; >>
У абстрактного класса не может быть объектов, но можно создать массив абстрактного класса, который будет содержать ссылки на объекты классов наследников:
public class FindAreas < public static void main(String[] args) < Figure[] figures = new Figure[3]; figures[0] = new Figure(10, 10); figures[1] = new Rectangle(10, 10); figures[2] = new Triangle(10, 10); for (Figure figure : figures) < double area = figure.caclulateArea(); System.out.println(area); >> >
Результат выполнения программы:
B области четырехугольника. 200.0 B области четырехугольника. 100.0 B области треугольника. 50.0
Иногда возникает необходимость определить класс, который не предполагает создания конкретных объектов. Например, класс фигуры. В реальности есть конкретные фигуры: квадрат, прямоугольник, треугольник, круг и так далее. Однако абстрактной фигуры самой по себе не существует. В то же время может потребоваться определить для всех фигур какой-то общий класс, который будет содержать общую для всех функциональность. И для описания подобных сущностей используются абстрактные классы.
Абстрактные классы - это классы, которые содержат или наследуют без переопределения хотя бы одну чистую виртуальную функцию. Абстрактный класс определяет интерфейс для переопределения производными классами.
Что такое чистые виртуальные функции (pure virtual functions)? Это функции, которые не имеют определения. Цель подобных функций - просто определить функционал без реализации, а реализацию определят производные классы. Чтобы определить виртуальную функцию как чистую, ее объявление завершается значением "=0". Например, определим абстрактный класс, который представляет геометрическую фигуру:
class Shape < public: virtual double getSquare() const = 0; // площадь фигуры virtual double getPerimeter() const = 0; // периметр фигуры >;
Класс Shape является абстрактным, потому что он содержит как минимум одну чистую виртуальную функцию. А в данном случае даже две таких функции - для вычисления площади и периметра фигуры. И ни одна из функций не имеет никакой реализации. В данном случае обе функции являются константными, но это необязательно. Гловно, чтобы любой производный класс от Shape должен будет предоставить для этих функций свою реализацию.
При этом мы не можем создать объект абстрактного класса:
Shape shape<>;
Для применения абстрактного класса определим следующую программу:
#include class Shape < public: virtual double getSquare() const = 0; // площадь фигуры virtual double getPerimeter() const = 0; // периметр фигуры >; class Rectangle : public Shape // класс прямоугольника < public: Rectangle(double w, double h) : width(w), height(h) < >double getSquare() const override < return width * height; >double getPerimeter() const override < return width * 2 + height * 2; >private: double width; // ширина double height; // высота >; class Circle : public Shape // круг < public: Circle(double r) : radius(r) < >double getSquare() const override < return radius * radius * 3.14; >double getPerimeter() const override < return 2 * 3.14 * radius; >private: double radius; // радиус круга >; int main() < Rectangle rect; Circle circle; std::cout
Здесь определены два класса-наследника от абстрактного класса Shape - Rectangle (прямоугольник) и Circle (круг). При создании классов-наследников все они должны либо определить для чистых виртуальных функций конкретную реализацию, либо повторить объявление чистой виртуальной функции. Во втором случае производные классы также будут абстрактными.
В данном же случае и Circle, и Rectangle являются конкретными классами и реализуют все виртуальные функции.
Консольный вывод программы:
Rectangle square: 1500 Rectangle perimeter: 160 Circle square: 2826 Circle perimeter: 188.4
Стоит отметить, что абстрактный класс может определять и обычные функции и переменные, может иметь несколько конструкторов, но при этом нельзя создавать объекты этого абстрактного класса. Например:
#include class Shape < public: Shape(int x, int y): x, y <> virtual double getSquare() const = 0; // площадь фигуры virtual double getPerimeter() const = 0; // периметр фигуры void printCoords() const < std::cout private: int x; int y; >; class Rectangle : public Shape // класс прямоугольника < public: Rectangle(int x, int y, double w, double h) : Shape, width(w), height(h) < >double getSquare() const override < return width * height; >double getPerimeter() const override < return width * 2 + height * 2; >private: double width; // ширина double height; // высота >; class Circle : public Shape // круг < public: Circle(int x, int y, double r) : Shape, radius(r) < >double getSquare() const override < return radius * radius * 3.14; >double getPerimeter() const override < return 2 * 3.14 * radius; >private: double radius; // радиус круга >; int main() < Rectangle rect; rect.printCoords(); // X: 0 Y: 0 Circle circle; circle.printCoords(); // X: 10 Y: 20 >
В данном случае класс Shape также имеет две переменных, конструктор, который устанавливает их значения, и невиртуальную функцию, которая выводит их значения. В производных классах также необходимо вызвать этот конструктор. Однако объект абстрактного класса с помощью его конструктора мы создать не можем.