реализация виртуальной функции и наследования в переполнении стека

Итак, у меня есть эти заголовочные файлы:

Shape.h:

class Shape
{
public:
Shape();
virtual ~Shape();
virtual double getArea();
virtual void printDraw();
bool isLegal(Shape shape);
};

Trig.h:

class Trig : public Shape
{
public:
Trig(Point pointA, Point pointB, Point pointC);
virtual ~Trig();
virtual double getArea();//override
virtual void printDraw();//override
bool isLegal(Trig trig);//override
};

но когда я пытаюсь реализовать Trig.cpp, я получаю ошибки.
Я старался :

Trig::Trig(Point pointA, Point pointB, Point pointC) {..}

Я просматривал Интернет, но я, кажется, не делаю наследство должным образом.
[Мой код ДОЛЖЕН иметь заголовочный файл, который включает только объявления! … Требования назначения!]

Я новичок в использовании как наследования, так и виртуальных функций в C ++ [Я использовал наследование в Java]

А что касается виртуальных функций .. есть ли разница в их реализации, чем в обычных функциях? [Я понимаю разницу в поведении].

2

Решение

В комментарий Вы объясняете это

«Я получаю сообщение об ошибке: неопределенная ссылка на Shape :: Shape ()»

Это означает, что вы забыли предоставить реализацию этого конструктора.

Теперь, когда техническая проблема решена, посмотрите на дизайн.

Первые два метода страдают от двух недугов: (1) хотя они никогда не должны мутировать объект, они не объявлены constпоэтому их нельзя вызывать на const объект и (2) get Префикс снижает читабельность, больше печатать и не имеет общего преимущества. Я нашел get Префикс полезен в некоторых редких случаях в качестве устройства для устранения неоднозначности, но все случаи использования, которые я видел новичков, были неадекватным копированием соглашения Java, что имеет смысл в Java, но не в C ++. Итак, вместо …

virtual double getArea();
virtual void printDraw();

делать

virtual double area() const;
virtual void print() const;

Затем метод …

bool isLegal(Shape shape);

неправильно во многих отношениях … Ой! Но начнем с чисто технического.

С чисто технической точки зрения излишне неэффективно передавать аргумент по значению, что влечет за собой операцию копирования для каждого вызова. Вместо этого передайте объект по ссылке. И сделать это ссылку на const, чтобы поддержать const объекты и rvalue объекты в качестве аргументов:

bool isLegal(Shape const& shape);

Далее, назвав: isLegal это плохое имя, потому что большинство любых объектов C ++ будут легальными. Это должно было бы быть, скажем, порнографические и проживание в незападных стране, для того, чтобы стать незаконным. И я не могу за жизнь мне думать о каком-либо способе сделать объект порнографического или сделать его постоянно находиться в каком-то конкретном географическом регионе.

Так,

bool isValid(Shape const& shape);

Далее, низкий уровень дизайна, нет веских причин, чтобыvirtual Метод как обычная функция-член, потому что для этого требуется, чтобы вы вызывали его для объекта. Но вся информация, в которой она нуждается, находится в обычном споре. Мы можем увидеть эту путаницу в производном классе, где …

bool isLegal(Trig trig);//override

это вовсе не переопределение: это технически перегрузка имени функции, что означает, просто другую функцию с тем же именем. Здесь нет виртуальности, нет переопределения. И это не нужно.

Итак, сделайте это static функция-член, которую не нужно вызывать для объекта:

static bool isValid(Shape const& shape);

Наконец, более высокий уровень проектирования, весь механизм конструкторов и деструкторов C ++ существует, чтобы избежать таких методов и проверок.

Идея в том, что вы …

  • Установите действительный объект в каждом конструкторе.

  • Сохраняйте объект действительным в каждом методе.

Тогда объект просто не может стать недействительным. Этот подход называется однофазное строительство, и свойства объекта, который делает его «действительным», известны как класс инвариант класса. Который должен быть установлен каждым конструктором и поддерживаться каждым методом.

Это означает, что окончательная версия isValid функция УСТРАНЕНУ него нет работы, потому что эта работа (должным образом) выполняется конструктором (-ами) и методами.

Хорошо, есть некоторые технические проблемы с однофазным построением, в частности, как сделать специфическую для производного класса инициализацию в конструкторе базового класса. Это покрыто C ++ FAQ. Часто полезно прочитать FAQ.

4

Другие решения

Первая версия верна:

Trig::Trig(Point pointA, Point pointB, Point pointC) {..}

Он скомпилируется, но не будет ссылаться. Причина в том, что у вас есть объявленный беспараметрический конструктор Shape, но вы не смогли определять Это. Эйхер добавить определение

Shape::Shape() {..}

или если конструктор по умолчанию в порядке, удалите объявление из заголовка Shape.

1

По вопросам рекламы [email protected]