Содержание
-
Иерархии классов, множественное наследование
Степанюк Константин Сергеевич 24const@gmail.com
-
Формулировка задания
Описать класс Person, имеющий поля firstNameи lastName Описать производный класс Studentрасширяющий класс Person, имеющий поле groupNum Для каждого поля описать (прототипы) функции селекторы и модификаторы Описать и реализовать виртуальную функцию print(), которая выводит список всех полей класса на экран
-
class Person { private: char* firstName; char* lastName; public: char* getFirstName(); char* getLastName(); void setFirstName(const char* _firstName); void setLastName(const char* _lastName); void print(); }; void Person::print() { cout
-
Правильный вариант
class Person { private: char* firstName; char* lastName; public: const char* getFirstName() const; const char* getLastName() const; void setFirstName(const char* _firstName); void setLastName(const char* _lastName); virtual void print(); }; void Person::print() { cout
-
Упражнение
Создать класс Region (регион). Класс имеет атрибуты start(начало) и length(длина). Создать класс Circle (круг). Класс имеет атрибуты centerX,centerY (координаты x и y) и radius (радиус). Требуется реализовать: 1. Селекторы 2. Модификаторы, генерирующие исключения BadAttributeExceptionесли атрибут не верный. 3. Функцию main() {…} с блоком try/catch, которая пытается создать регион с неверными атрибутами и выводит сообщение о соответствующей ошибке в блоке catch.
-
Сокрытие членовкласса
classBase { public: voidf (int); voidf (double); }; class D: publicBase { public: voidf (char); //f скрывает ВСЕ функции Base::f }; Если в производном классе объявлен член с тем же именем что и в базовом, то он скрывает все одноименные члены базового класса без учета правил перегрузки
-
Разрешение имен
Разрешение члена класса при доступе осуществляется на основании типа используемой переменной (ссылки, указателя) за исключением виртуальных функций при использовании ссылок и указателей. class Base { public: void f(); virtual void g(); }; class Derived: public Base { public: void f(); virtual void g(); }; int main() { Derived d; Base b = (Base)d; Base *bp = new Derived(); Base &r = d; b.f(); b.g(); bp->f(); bp->g(); r.f(); r.g(); } //Base::f //Base::g //Base::f //Derived::g //Base::f //Derived::g
-
Абстрактные классы
class Shape { private: Point center; protected: const Point& getCenter() const {return center;} public: virtual void paint(Graphics&) const = 0; virtual void rotate(double angle) = 0; void move(Point to) { center = to; } }; class Circle :public Shape { private: double radius; public: virtual void paint(Graphics &g) const {…} virtual void rotate(double angle) {} }; Класс Shape –абстрактный класс (не все функции определены) Аналогом интерфейса является абстрактный класс, у которого все функции являются чисто виртуальными и все поля являются статическими константами
-
Избегайте переопределения наследуемых функций
class B { public: void mf() {…} }; class D: public B { public: void mf() {…} //!Сокрытие }; int main() { D x; D *pd = &x; B *pb = &x; pd->mf(); //D::mf pb->mf();//B::mf –неинвариантное поведение объекта }
-
Не переопределяйте наследуемое значение аргумента по умолчанию
enumShapeColor {RED, GREEN, BLUE}; class Shape { public: virtual void draw(ShapeColor color = RED) const=0; }; class Rectangle : public Shape { public: virtual void draw(ShapeColor color) const {…}; }; class Circle : public Shape { public: virtual void draw(ShapeColor color = GREEN) const {…} }; Shape *ps; Circle *pc = new Circle(); Rectangle *pr = new Rectangle(); ps = pr; ps->draw(); //Rectangle::draw(RED) ps = pc; ps->draw(); //Circle::draw(RED) !!! pc->draw();//Circle::draw(GREEN) !!!
-
Множественное наследование
class A { public: virtual void f(); }; class B { public: virtual void f(); virtual void g(); }; class C: public A, public B { public: virtual void f(); }; C *pc = new C(); B *pb = pc; //сдвиг на delta(B) pb -> f(); //thunk_bcf
-
Проблемы множественного наследования
Множественное наследование обычно используется в следующих случаях: Возникает желание переиспользовать уже написанный код в рамках самого проекта Необходимо воспользоваться разнородными библиотеками и обеспечить возможность для объекта одновременно использоваться в этих разных библиотеках Основные проблемы: Возможное нарушение ORR (Oneresponsibilityrule)–правила единственности ответственности (абстракции) Проблема с пересечением имен методов наследованных из разных базовых классов
-
Какую из двух функций doSomething наследует класс Derived?
-
Проблема ромбовидной иерархии
Derived d = Derived(); ParentA *pa = &d; ParentB *pb = &d; Base *bp = &d; // Какая часть Base будет использоваться?
-
Альтернатива множественному наследованию
Использовать множественное наследование только чистых абстрактных базовых классов, при этом допустимо наследование от одного конкретного базового класса В ситуациях когда базовые классы от которых возникает желание унаследовать новый класс разрабатываются в рамках одного проекта, лучше ввести дополнительные чистые абстрактные классы (интерфейсы) и воспользоваться агрегацией
-
-
using директива
Данная директива позволяет решать проблему неопределенности и специфицировать доступ к методам базовых классов в производном классе class BaseA { public: void bar(); void foo( char ); }; class BaseB { public: void bar(); void foo( int ); }; class Derived :public BaseA,publicBaseB { public: using BaseA::bar; using BaseA::foo; using BaseB::foo; void foo(); }; Derived d; d.bar(); //BaseA::bar d.foo(‘a’); //BaseA::foo d.foo(1); //BaseB::foo
-
Виртуальные базовые классы
Повторное наследование: class Base { }; class A: public Base { }; class B: public Base { }; //Класс наследует два экземпляра полей из класса Base class Derived: public A, public B { }; Виртуальный базовый класс class Base { }; class A: public virtual Base { }; class B: public virtual Base { }; //Часть относящаяся к Base является общей class Derived: public A, public B { }; Нельзя приводить из типа виртуальной базы: Base *bp = new Derived(); (Derived*) bp; //error!!!
-
Информация о типе на этапе исполнения
class type_info { public: virtual ~type_info(); int operator==(const type_info& rhs) const; int operator!=(const type_info& rhs) const; int before(const type_info& rhs) const; const char* name() const; const char* raw_name() const; private: ... }; Class c; const type_info& ti = typeid(c); ti.name();
-
Динамическое приведение типов
dynamic_cast (expr); Применим только для полиморфных типов (тип выражения expr должен быть полиморфным) Позволяет безопасно приводить тип от базового класса к производному, а также между родственниками (кросс-приведение типа) Может применяться для приведения указателей и ссылок В случае приведения для ссылок может выбрасывать исключение bad_cast
-
Применение dynamic_cast
class Base { public: virtual ~Base(); }; class A: public Base {}; class B{}; class C: public A, public B {}; Base *bpc = new C(); Base &brc = C(); Base *bpa = new A(); Base &bra = A(); A *ap = dynamic_cast(bpc); //Ок B *bp = dynamic_cast(bpa); // 0 –нулевой указатель A &ra = dynamic_cast(brc); //Ok B &rb = dynamic_cast(bra); //bad_cast exception
-
Задание
Реализовать чисто абстрактные классы Danceableи Singable, описывающие методы dance()и sing() соответственно, (выводящие на экран сообщение). Реализовать класс Person, имеющий поля firstNameи lastName Реализовать класс Actorнаследующий классы Person, Danceable, Singable
Нет комментариев для данной презентации
Помогите другим пользователям — будьте первым, кто поделится своим мнением об этой презентации.