Разделы презентаций


Множественное наследие

Содержание

Варианты…НаследованиеОдиночное наследованиеМножественное наследованиеПри множественном наследовании объекты производных классов могут использовать данные и методы нескольких классов, а также в свою очередь быть базовыми классами для других.

Слайды и текст этой презентации

Слайд 1Тест с отчетом 1
1) Скомпилируется ли следующий код:
class Clazz {

};
(да/нет)
2) Перечислите все правильные способы объявления локальной константы в блоке

кода.

(1) #const size = 5;
(2) define const size 5
(3) const int size;
(4) const int size = 5;

(перечислите номера)

3) Что будет выведено на экран в результате компиляции и выполнения следующего кода?

Варианты ответа:

(1) Ошибка компиляции
(2) 1711
(3) 2323
(4) Ошибка выполнения
(5) 2424

(укажите номер)

#include
 
int a = 23;
 
int main(int argc, char * argv[])
{
++--++--++--++--++--++--a;
++a; std::cout << a; --a;
++--++--++--++--++--++--a;
++a; std::cout << a; --a;
++--++--++--++--++--++--a;
}




Тест с отчетом 11) Скомпилируется ли следующий код:class Clazz { };(да/нет)2) Перечислите все правильные способы объявления локальной

Слайд 2Варианты…
Наследование

Одиночное наследование
Множественное наследование
При множественном наследовании объекты производных классов могут использовать

данные и методы нескольких классов, а также в свою очередь

быть базовыми классами для других.
Варианты…НаследованиеОдиночное наследованиеМножественное наследованиеПри множественном наследовании объекты производных классов могут использовать данные и методы нескольких классов, а также

Слайд 3Множественное наследование - определение
class D: атрибут_наследования base1, …, атрибут_наследования baseN
{
.

. .
};
Атрибуты наследования и их смысл тот же, что и

при одиночном наследовании.

Данная последовательность базовых классов определяет порядок вызова конструкторов базовых классов.

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

При уничтожении объекта производного класса деструкторы вызываются в обратном порядке вызовам конструкторов.
Множественное наследование - определениеclass D: атрибут_наследования base1, …, атрибут_наследования baseN{. . .};Атрибуты наследования и их смысл тот

Слайд 4Аргументы конструкторов
Конструктор_производного_класса (список аргументов) :
base1 (список аргументов), …, baseN

(список аргументов)
{
. . .
}
Как и для одиночного наследования, если конструктор

или конструкторы базового класса содержат как минимум один аргумент, то производный класс также должен содержать конструктор.

Если конструктор базового класса имеет аргументы без умолчания, то их надо передать через конструктор производного класса.

При описании конструктора производного класса задаются те конструкторы базовых классов, которые имеют аргументы.

Если конструктор базового класса не имеет аргументов, или все аргументы такого конструктора используются по умолчанию, то имя такого конструктора можно на задавать в описании производного класса.

Список конструкторов базовых классов не влияет на порядок их вызова. Он определяется только списком имен базовых классов в начале определения производного класса!

Аргументы конструкторовКонструктор_производного_класса (список аргументов) : base1 (список аргументов), …, baseN (список аргументов){. . .}Как и для одиночного

Слайд 5Виртуальные базовые классы
class A { . . . };
class B:

public A, protected A { . . . }; //Нельзя!
В

С++ запрещено непосредственно передавать базовый класс в производный более одного раза, т.е. имя класса в списке базовых классов повторяться не может.

Однако могут возникать ситуации, когда один производный класс косвенно может наследовать один и тот же базовый класс через другие базовые классы. Например:

class A
{
public:
int n;
. . .

};

class B: public A
{
. . .
};

class C: public A , public B
{
. . .
};



Виртуальные базовые классыclass A { . . . };class B: public A, protected A { . .

Слайд 6

Виртуальные базовые классы - пример
Объект класса A
int n;
Объект класса B
Объект

класса A
int n;

Объект класса C
Объект класса A
int n;

Объект класса B
Объект

класса A

int n;

Ситуация неоднозначности:
С obj;
obj.n=0; // Ошибка

По примеру получается такая структура объектов

Виртуальные базовые классы - примерОбъект класса Aint n;Объект класса BОбъект класса Aint n;Объект класса CОбъект класса Aint

Слайд 7Виртуальные базовые классы - пример
Такое наследование вполне возможно и компилятор

не выдаст сообщение об ошибке, а только предупредит, что наследуемый

класс А также находится в наследуемом классе B.

В данном примере ошибка возникнет на стадии компиляции. Компилятор не различит, какую именно переменную с именем n базового класса необходимо изменить: или переменную , которая непосредственно является компонентой класса A, или переменную, которая доступна из наследуемого класса B?

Решить такую проблему в С++ можно путем использования виртуальных базовых классов.

Виртуальные базовые классы - примерТакое наследование вполне возможно и компилятор не выдаст сообщение об ошибке, а только

Слайд 8Виртуальные базовые классы - пример
class A { . . .

};
class B: virtual public A { . . . };
class

C: virtual public A, public B { . . . };

Если один базовый класс косвенно наследуется в одном производном классе и наследуется с атрибутом virtual, то в экземпляр производного класса будет помещена только одна копия базового класса.
Базовый класс объявляется как виртуальный только при наследовании – в списках базовых классов с указанием спецификации virtual.

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

Виртуальные базовые классы - примерclass A { . . . };class B: virtual public A { .

Слайд 9Множественное наследование на примере (1)
#include
using namespace std;

class A {
public:
int

a;
A(int a) {this->a =a; cout

~A() {cout << " Destructor A\n"; }
void print() { cout << "a = " << a << endl; }
};

class B {
public:
int b;
B(int b) {this->b =b; cout << " Constructor B\n"; }
~B() {cout << " Destructor B\n"; }
void print() { cout << "b = " << b << endl; }
};

Множественное наследование на примере (1)#include using namespace std;class A {public:	int a;	A(int a) {this->a =a; cout

Слайд 10Множественное наследование на примере (2)
class C : virtual public A{
public:

int c;
C(int c): A(c) {this->c =c; cout

Constructor C\n"; }
~C() {cout << " Destructor C\n"; }
void print() { cout << "c = " << c << endl; }
};

class D : public B, virtual public C, virtual public A{
public:
int d;
D(int d): A(d+1), B(d+2), C(d+3) {this->d =d; cout << " Constructor D\n"; }
~D() {cout << " Destructor D\n"; }
void print()
{
cout << "d = " << d << endl; A::print(); B::print(); C::print();
}
};
Множественное наследование на примере (2)class C : virtual public A{public: int c; C(int c): A(c) {this->c =c;

Слайд 11Множественное наследование на примере

Результат:
void f()
{
D obj(1);
obj.print();
}
void main()
{

f();
char s; std::cin>>s;
}

При виртуальном наследовании базовых классов в первую

очередь вызываются конструкторы виртуальных базовых классов в порядке наследования.
Множественное наследование на примереРезультат:void f(){ D obj(1); obj.print();}void main() { f(); char s; std::cin>>s;}При виртуальном наследовании базовых

Слайд 12Множественное наследование на примере

Результат:
… class C : virtual public

A{ …

… class D : public B, virtual public C,

virtual public A
Множественное наследование на примереРезультат:…  class C : virtual public A{ …… class D : public B,

Слайд 13Множественное наследование на примере

Результат:
… class C : : virtual

public A{ …

… class D : public B, : virtual

public C,
virtual public A

Множественное наследование на примереРезультат:…  class C : : virtual public A{ …… class D : public

Слайд 14Множественное наследование на примере

Результат:
… class C : : virtual

public A{ …

… class D : public B, : virtual

public C,
virtual public A

Множественное наследование на примереРезультат:…  class C : : virtual public A{ …… class D : public

Слайд 15Рассмотрим пример программы, которая основана на использовании виртуальных функций.
Организация списка

разнородных элементов
Предположим, что необходимо создать список элементов разных типов, например

int и char*. Любой элемент вне зависимости от его типа может принадлежать какому-то множеству. Необходимо также создать функции, которые выводили бы значения элементов, принадлежащих заданному множеству, а также удаляли бы из списка элементы заданного множества. Принадлежность элемента тому или иному множеству задается при помощи идентификатора множества.
Рассмотрим пример программы, которая основана на использовании виртуальных функций.Организация списка разнородных элементовПредположим, что необходимо создать список элементов

Слайд 16Абстрактный базовый класс для организации списка
Пример программы (1)
#include
using namespace

std;
class base {

// Базовый класс
protected:
base *next; // Следующий элемент
base *prev; // Предыдущий элемент
int num; // Идентификатор множества
static base *start; // Указатель начала списка
static int NmOb; // Количество элементов в списке
public:
base(int); // Конструктор
virtual void print() = 0; // Чисто виртуальная функция печати элемента
static void printall(int); // Печать всех элементов заданного множества
static void del(int); // Удаление всех элементов заданного множества
};

base *base::start=NULL; // Начало списка
int base::NmOb=0; // Число элементов списка

Абстрактный базовый класс для организации спискаПример программы (1)#include using namespace std;class base {

Слайд 17Абстрактный базовый класс для организации списка
Пример программы (1)

Абстрактный базовый класс для организации спискаПример программы (1)

Слайд 18Конструктор и метод печати заданного множества
Пример программы (2)
base::base(int n)
{
num

= n; // Идентификатор множества
NmOb++;

// Счетчик множеств
next = start; // Первый элемент списка
if (start != NULL) // в списке уже были элементы?
start ->prev = this;
start = this;
start->prev = NULL;
}

void base::printall(int n)
{
base *p = start;
for (int i=0; i < NmOb; p = p -> next, i++)
if (p->num == n) p -> print();
}
Конструктор и метод печати заданного множестваПример программы (2)base::base(int n){ num = n;   // Идентификатор множества

Слайд 19Метод удаления заданного множества
Пример программы (3)
void base::del(int n)
{
int i=NmOb;

for (base *tmp = start; i>0; tmp = tmp ->

next, i--)
if (tmp -> num == n) {
if (tmp == start) start =tmp -> next;
else tmp-> prev -> next = tmp -> next;
delete tmp;
}
}
Метод удаления заданного множестваПример программы (3)void base::del(int n){ int i=NmOb; for (base *tmp = start; i>0; tmp

Слайд 20Базовый класс для работы с множествами
Пример программы (4)
class Set
{

static int Last_id;
int id;
public:
Set() { id = ++Last_id;

}
~Set() { base::del(id); }
inline int get_id () { return id; }
friend ostream &operator<<(ostream &, Set&);
};

int Set::Last_id = 0;


ostream &operator<<(ostream &os, Set&s)
{
base::printall(s.id);
return os << endl;
}

Перегрузка вывода в поток

Базовый класс для работы с множествамиПример программы (4)class Set { static int Last_id; int id;public: Set() {

Слайд 21Элемент множества – целое число
Пример программы (5)
class Integer: public base


{
int i;
public:
Integer(int i, int num): base(num)
{this

-> i = i;}
void print() { cout << i << ' '; }
inline int& get() { return i; }
};


class String: public base
{
char * str;
public:
String(char * str, int num): base(num)
{this -> str = str;}
void print() { cout << str << ' '; }
};

Элемент множества – строка символов

Элемент множества – целое числоПример программы (5)class Integer: public base { int i;public: Integer(int i, int num):

Слайд 22Головная программа - тест
Пример программы (6)
void main(int argc, char *

argv[])
{
Set* s1= new Set;
int id1=s1->get_id(), id2;
Integer* t1=

new Integer(1,id1);
Integer* t2 = new Integer(5,id1);
String* t3 = new String("str1", id1);
String* t4 = new String("str2", id1);
{
Set* s2 = new Set;
id2 = s2->get_id();
String* t5 = new String("hello", id2);
Integer* t6 = new Integer(12,id2);
cout << (*s1) << (*s2);
}
base::printall(id1);

char xxx; cin >> xxx;
}

Слайд 23 Виртуальная функция и ее порожденные экземпляры, имеющие одну и

ту же сигнатуру, должны иметь один и тот же возвращаемый

тип. Перекрытие виртуальной функции называется переопределением.
Внимание! Невиртуальные функции–члены, имеющие ту же самую сигнатуру в порожденных классах, могут иметь различный возвращаемый тип.
Конструкторы и деструкторы не имеют возвращаемых типов. Тип, возвращаемый перегруженным оператором new должен быть void*. Тип, возвращаемый перегруженным оператором delete должен быть void.
Все функции-члены, за исключением конструкторов и перегруженных операторов new и delete, могут быть виртуальными.
Конструкторы, деструкторы, перегруженный operator= и friend функции не наследуются.

Повтор некоторых деталей - 1

Виртуальная функция и ее порожденные экземпляры, имеющие одну и ту же сигнатуру, должны иметь один и

Слайд 24 Перегрузка операторов =, (), [] и -> может быть

выполнена только нестатическими функциями-членами. Перегрузка операторов new и delete может

быть выполнена только статическими функциями-членами. Прочие перегружаемые операторы могут быть выполнены любыми другими функциями, дружественными или обычными. Операторы ввода/вывода потоков >> и << не могут перегружаться функциями-членами класса – только дружественными.
Union могут иметь конструкторы и деструкторы, но не виртуальные функции. Union не может ни служить базовым классом, ни иметь базового класса.
Модификация доступа при наследовании возможна, но его использование с общим наследованием разрушает связь подтипов. Модификация доступа не может расширять видимость.

Повтор некоторых деталей - 2

Перегрузка операторов =, (), [] и -> может быть выполнена только нестатическими функциями-членами. Перегрузка операторов new

Слайд 25 Термин перегрузка относится к использованию одного и того же

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

от типов параметров, используемых оператором или функцией.
Список параметров функции называется сигнатурой. При проверке сигнатуры существует три возможности: наилучшее соответствие, неоднозначное соответствие и отсутствие соответствия. Без наилучшего соответствия компилятор выдает соответствующую ошибку синтаксиса.

Повтор некоторых деталей - 3

Термин перегрузка относится к использованию одного и того же имени для множества значений оператора или функции.

Слайд 26Пусть функция print описана как
void print( int i =

0); // сигнатура int
void print( int i, double x);

// сигнатура int, double
void print(double x, int i); // сигнатура double, int

Вызов:
print (‘A’); // преобразует и соответствует int
print (str[]); // нет соответствия – неправильный тип
print (15,9); // неоднозначно
print (); // соответствует int по умолчанию
print (15, 9.2); // соответствует int, double

Повтор некоторых деталей - 4

Пусть функция print описана как void print( int i = 0);  // сигнатура intvoid print( int

Слайд 27Существует два этапа алгоритма выбора соответствия сигнатуры. Первый этап определяет

лучшее соответствие для каждого параметра. На втором этапе проверяется, есть

ли функция, которая уникально лучше всего соответствует по каждому параметру.
Лучшее соответствие – это значит точное соответствие. Оно также включает в себя и тривиальные преобразования.
Из В Из В
T T& T* const T*
T& T T* volatile T*
T const T T& const T&
T volatile T T& volatile T&
T[ ] T*
T (параметры) (*T) (параметры)

Повтор некоторых деталей - 5



Эти преобразования не могут использоваться для абсолютно однозначного точного соответствия.

Существует два этапа алгоритма выбора соответствия сигнатуры. Первый этап определяет лучшее соответствие для каждого параметра. На втором

Слайд 28Алгоритм выбора перегруженных функций:

Использовать точное соответствие, если оно найдено.
Проверить поддержку

стандартных типов
Проверить стандартные преобразования типов
Проверить преобразования, определяемые пользователем
Использовать соответствие для

аргументов, если оно найдено

Повтор некоторых деталей - 6

Алгоритм выбора перегруженных функций:Использовать точное соответствие, если оно найдено.Проверить поддержку стандартных типовПроверить стандартные преобразования типовПроверить преобразования, определяемые

Слайд 29Тесты …
Вопрос: Что напечатает программа:

#include
 
void ampersand( int n,

int &k );
 
int main()
{
int n=5;

int k=10;

ampersand( n, k );
printf( "n=%d &k=%d\n", n, k );
 
return 0;
}
 
void ampersand( int n, int &k )
{
k -= 5;
--n;
}

Варианты ответа:

(1) Произойдет ошибка во время компиляции
(2) n=5 & k=10
(3) n=5 & k=5
(4) n=5 & k=<адрес переменной в памяти>


Слайд 30Тесты …
Вопрос: Что напечатает программа:

#include
 
void ampersand( int n,

int &k );
 
int main()
{
int n=5;

int k=10;

ampersand( n, k );
printf( "n=%d &k=%d\n", n, k );
 
return 0;
}
 
void ampersand( int n, int &k )
{
k -= 5;
--n;
}

Варианты ответа:

(1) Произойдет ошибка во время компиляции
(2) n=5 & k=10
(3) n=5 & k=5
(4) n=5 & k=<адрес переменной в памяти>



Слайд 31Тесты …
Вопрос: в каких строках есть ошибки:


class A {

void Test() const; // 1
};
void A::Test()

const; // 2
void A::Test() const {} // 3
 
void Test() const; // 4
void Test() const {} // 5
Тесты …Вопрос: в каких строках есть ошибки: class A { void Test() const;

Слайд 32Тесты …
Вопрос: в каких строках есть ошибки:


class A {

void Test() const; // 1
};
void A::Test()

const; // 2
void A::Test() const {} // 3
 
void Test() const; // 4
void Test() const {} // 5




Тесты …Вопрос: в каких строках есть ошибки: class A { void Test() const;

Слайд 33Тесты …
Вопрос: Что будет выведено на экран?


#include
class A
{
public:

A(void){std::cout

public A
{
public:
B(void){std::cout << "B";}
~B(void){std::cout << "b";}
};
int main(void)
{
B b;
return 0;
}
Тесты …Вопрос: Что будет выведено на экран? #include class A{public:  A(void){std::cout

Слайд 34Тесты …
Вопрос: Что будет выведено на экран?


#include
class A
{
public:

A(void){std::cout

public A
{
public:
B(void){std::cout << "B";}
~B(void){std::cout << "b";}
};
int main(void)
{
B b;
return 0;
}

A B b a

Тесты …Вопрос: Что будет выведено на экран? #include class A{public:  A(void){std::cout

Обратная связь

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

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика