1 2 3 4 5 6 7 8 9 10 11 12 |
//Листинг #1 Visual Studio 2015 class Base {}; //Базовый класс class A : public Base {}; //Производный класс int main() { Base base; A a; Base *ptr; //указатель на базовый класс может указывать на любой объект равный себе или любой нижний по иерархии ptr = &base; //на объект базового класса ptr = &a; //на объект-наследника } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
//Листинг #2 Visual Studio 2015 #include <iostream> using std::cout; using std::cin; struct Base{ virtual void type(){ cout << "type: struct Base\n"; } }; struct A : public Base { void type() { cout << "type: struct A\n"; } }; struct B : public A { void type() { cout << "type: struct B\n"; } }; int main() { Base base; A a; B b; Base *ptr; //указатель на базовый класс может указывать на любой объект равный себе или нижний по иерархии ptr = &base; //на объект базового класса ptr->type(); //Тип объекта, на который указывает ptr, автоматически определился правильно, это Base ptr = &a; //на объект-наследника ptr->type(); //Тип объекта, на который указывает ptr, автоматически определился правильно, это A ptr = &b; //на объект-наследника ptr->type(); //Тип объекта, на который указывает ptr, автоматически определился правильно, это B cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//Листинг #3 Visual Studio 2015 #include <iostream> using std::cout; using std::cin; struct Base{ virtual void type(){ cout << "type: struct Base\n"; } }; struct A : public Base { void type() { cout << "type: struct A\n"; } void some_function() { cout << "some_function from struct A\n"; } }; struct B : public A { void type() { cout << "type: struct B\n"; } }; int main() { Base base; A a; B b; Base *ptr; //указатель на базовый класс может указывать на любой объект равный себе или нижний по иерархии ptr = &a; //Ссылаемся на некоторого наследника, в котором описана независимая функция ptr->type(); //Вызов полиморфной функции, тип определяется ptr->some_function(); //Вызов независимой внутренней для объекта, на который сослан указатель, не компилируется cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
//Листинг #4 Visual Studio 2015 #include <iostream> using std::cout; /*прототипы*/ class TFish; void foo(TFish *); /*классы*/ class TFish{ //Базовый класс РЫБА public: virtual void swim(){ //виртуальная функция cout << "fish swim\n"; } }; /*Класс ТУНЕЦ, производный от класса РЫБА*/ class TTuna: public TFish{ public: void swim(){ cout << "Tuna sweam in sea\n"; } void play(){ //своя функция для тунца cout << "play with tuna\n"; } }; /*Класс КАРП, производный от класса РЫБА*/ class TCarp: public TFish{ public: void swim(){ cout << "Carp sweam in lake\n"; } void say(){ cout << "say with carp"; //своя функция для карпа } }; /*Функция, которая не является частью иерархии класса РЫБА*/ void foo(TFish* fish){ //функция foo Принимает параметр fish, который есть указатель на класс TFish TTuna* tuna = dynamic_cast<TTuna*>(fish); //Приведение указателя на базовый класс к указателю на производный класс if (tuna){ //Проверка на успешное приведение tuna->play(); //Если всё ОК, то что-то делается с объектом } TCarp* carp = dynamic_cast<TCarp*>(fish); //Аналогично if (carp){ carp->say(); } } int main(){ TTuna tuna; foo(&tuna); //Отдаём функции объект типа Тунец TCarp carp; foo(&carp); //Отдаём функции объект типа Карп cin.get() } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
//Листинг #5 #include <iostream> using std::cout; using std::cin; /*прототипы*/ class TFish; void foo(TFish *); /*классы*/ class TFish { //Базовый класс РЫБА public: virtual void swim() { //виртуальная функция cout << "fish swim\n"; } }; /*Класс ТУНЕЦ, производный от класса РЫБА*/ class TTuna : public TFish { public: void swim() { cout << "\n============= Tuna sweam in sea =============\n\n"; } void play() { //своя функция для тунца cout << "play with tuna\n\n"; } }; /*Класс КАРП, производный от класса РЫБА*/ class TCarp : public TFish { public: void swim() { cout << "\n============= Carp sweam in lake =============\n\n"; } void say() { cout << "say with carp"; //своя функция для карпа } }; void foo(TFish* fish) { //Как нам определить тип объекта, пришедшего сюда в нужный моментт? Тунец ли это, карп ли это? fish->swim(); //Полиморфную функцию мы можем вызвать без проблем //Но как быть с неполиморфной? //В зависимости от выбора нужно вызвать либо play(), присущую TCarp, либо say(), присущую TTuna //Один из способов: узнать будущее и предсказать, но это подойдёт только одному, двум пользователям //Другой способ: наделать костылей, подмешав в классы признаки-опознователи //Третий способ: распознать тип объекта, с которым в настоящий момент связан указатель fish, используемый как параметр } int main() { TTuna tuna; TCarp carp; int i = 1; while (i) { cout << "input case: \n"; //Выберите рыбу cout << "1. Tuna\n"; cout << "2. Carp\n"; cout << "0. Exit\n"; cin >> i; switch (i) { case 1: foo(&tuna); break; case 2: foo(&carp); break; } } cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
//Листинг #6 #include <iostream> using std::cout; using std::cin; /*прототипы*/ class TFish; void foo(TFish *); /*классы*/ class TFish { //Базовый класс РЫБА public: virtual void swim() { //виртуальная функция cout << "fish swim\n"; } }; /*Класс ТУНЕЦ, производный от класса РЫБА*/ class TTuna : public TFish { public: void swim() { cout << "\n============= Tuna sweam in sea =============\n"; } void play() { //своя функция для тунца cout << "============= play with tuna =============\n\n"; } }; /*Класс КАРП, производный от класса РЫБА*/ class TCarp : public TFish { public: void swim() { cout << "\n============= Carp sweam in lake =============\n"; } void say() { cout << "============= say with carp =============\n\n"; //своя функция для карпа } }; void foo(TFish* fish) { fish->swim(); //Полиморфную функцию мы можем вызвать без проблем TTuna *tuna = dynamic_cast<TTuna*>(fish); //Задаёмся вопросом, можем ли мы безопасно свести указатель на TFish к указателю на TTuna TCarp *carp = dynamic_cast<TCarp*>(fish); //Задаёмся вопросом, можем ли мы безопасно свести указатель на TFish к указателю на TCarp if (tuna) { //Если указатель fish смог быть сведён к указателю, указывающему на TTuna tuna->play(); //То вызываем нужную функцию из класса TTuna } else if (carp){ //Если указатель fish смог быть сведён к указателю, указывающему на TCarp carp->say(); //То вызываем функции из класса TCarp } } int main() { TTuna tuna; TCarp carp; int i = 1; while (i) { cout << "input case: \n"; //Выберите рыбу cout << "1. Tuna\n"; cout << "2. Carp\n"; cout << "0. Exit\n"; cin >> i; switch (i) { case 1: foo(&tuna); break; case 2: foo(&carp); break; } } cin.get(); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//Листинг #7 Взято из учеьника Прата //пусть имеется подобная иерархия class Grand { // содержит виртуальные методы }; class Superb : public Grand { ... }; class Magnificent : public Superb { ... }; //пусть имеются перечисленные ниже указатели: Grand * pg = new Grand; Grand * ps = new Superb; Grand * pm = new Magnificent; //и имеются следующие приведения типов Magnificent *p1 =(Magnificent *) pm; // #1 Magnificent *p2 =(Magnificent *) pg; // #2 Superb *p3 =(Magnificent *) pm; // #3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
//Листинг #8 из учебника Прата #include <ctime> #include <cstdlib> #include <iostream> using std::cout; /*ИЕРАРХИЯ КЛАССОВ*/ class Grand{ int hold; public: Grand(int h=0):hold(h){} virtual void Speak() const { cout << "I'm a grang class!\n";} virtual int Value() const { return hold; } virtual ~Grand(){} }; class Superb: public Grand{ public: Superb(int h = 0):Grand(h){} void Speak() const { cout << "I'm a superb class!!\n"; } virtual void Say() const{ cout << "I hold the superb value of " << Value() << '\n'; } }; class Magnificent: public Superb{ char ch; public: Magnificent(int h = 0, char c = 'A'):Superb(h),ch(c){} void Speak() const { cout << "I'm a magnificent class!!!\n"; } void Say() const { cout << "I hold the character ch " << ch << " and the integer " << Value() << '\n'; } }; /*КОНЕЦ ИЕРАРХИИ КЛАССОВ*/ Grand* GetOne(); //прототип функции, возвращающей адрес объекта случайного типа int main(){ srand(std::time(0)); Grand *pg; //В pg будет записываться адрес объекта случайного типа Superb *ps; //ps будет использован для вызова метода Say for (auto i=0; i<5; i++){ pg = GetOne(); pg->Speak(); if( ps = dynamic_cast<Superb *>(pg)) ps->Say() ; //Проверка на успешность (безопасность) и выполнения метода Say cout << '\n'; } } /*генерация объекта случайного типа*/ Grand* GetOne(){ Grand *p; switch (rand()%3){ case 0: p = new Grand (rand() % 100); break; case 1: p = new Superb (rand () % 100); break; case 2: p = new Magnificent (rand() % 100, 'A' + rand() % 26); break; } return p; //возврат указателя на объект типа Grand } |
Добавить комментарий