Форум программистов, компьютерный форум CyberForum.ru

Исключение для чисто виртуальной функции - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 13, средняя оценка - 4.62
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
23.08.2013, 18:45     Исключение для чисто виртуальной функции #1
Читал вопросы на собеседованиях по С++ и столкнулся с pure virtual function call исключение. Объясните пожалуйста зачем это нужно ?! В моем понимании чист. вирт. функц. созданая для того что бы никто не создавал объекты этого класса.
Ссылка на источник http://habrahabr.ru/post/117996/ и копия ответа:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
10. Как сгенерировать pure virtual function call исключение?
 
Ответ: Нужно вызвать чисто виртуальный метод в конструкторе родительского класса т.е. до создания дочернего, в котором этот метод реализован. Т.к. современный компилятор не даст это сделать напрямую, то нужно будет использовать промежуточный метод.
Пример:
class Base
{
public:
    Base()
    {
        base_func();
    }
    void base_func()
    {
        func(); // pure virtual function call exception
    }
    virtual void func() = 0;
};
class Derived : public Base
{
public:
    virtual void func()
    {
    }
};
Здесь нет ни throw генерировавшего некое исключение, ни объявления исключений
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Kuzia domovenok
 Аватар для Kuzia domovenok
1883 / 1738 / 116
Регистрация: 25.03.2012
Сообщений: 5,907
Записей в блоге: 1
23.08.2013, 18:56     Исключение для чисто виртуальной функции #2
Вот это да! Я понимаю, что так не должно работать, но никогда бы не подумал, что это скомпилируется! Точнее, вообще никогда не задумывался написать так!

Кстати, а как тогда поведёт себя эта программа? В Debug я словил исключение. А при запуске релизного экзешника что будет твориться?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,917
Записей в блоге: 2
Завершенные тесты: 1
23.08.2013, 18:59     Исключение для чисто виртуальной функции #3
Цитата Сообщение от ArkTaS Посмотреть сообщение
Здесь нет ни throw генерировавшего некое исключение, ни объявления исключений
Ну и что? Объект еще не создан а уже идет обращение к его членам

Добавлено через 24 секунды
Цитата Сообщение от Kuzia domovenok Посмотреть сообщение
Я понимаю, что так не должно работать, но никогда бы не подумал, что это скомпилируется!
То что скомпилировалось не всегда работает

Добавлено через 2 минуты
Цитата Сообщение от ArkTaS Посмотреть сообщение
Объясните пожалуйста зачем это нужно ?
Например, чтобы проверить как Вы разбираетесь в наследовании и в полиморфизме в частности
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.08.2013, 19:43     Исключение для чисто виртуальной функции #4
Kuzia domovenok, Право, очень странно задавать такие вопросы, учитывая что мы пишем на языке UB++.
Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a
virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed)
from such a constructor (or destructor) is undefined.
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
23.08.2013, 20:43  [ТС]     Исключение для чисто виртуальной функции #5
Цитата Сообщение от Croessmah Посмотреть сообщение
Например, чтобы проверить как Вы разбираетесь в наследовании и в полиморфизме в частности
И в чем здесь проявляется полиморфизм имею ввиду косвенный вызов чистой вирт. функции ?
Зачем в 17 и 22 строке дважды писать virtual ? Как словить это исключение, какой тип писать ? и зачем это вообще делать, если эффект андефайнед ?
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
23.08.2013, 20:49     Исключение для чисто виртуальной функции #6
Цитата Сообщение от ArkTaS Посмотреть сообщение
Зачем в 17 и 22 строке дважды писать virtual ?
Хороший стиль программирования.
Цитата Сообщение от ArkTaS Посмотреть сообщение
Как словить это исключение, какой тип писать ?
Это не языковое исключение (всмысле не те exception, которые есть в С++).
Цитата Сообщение от ArkTaS Посмотреть сообщение
и зачем это вообще делать, если эффект андефайнед ?
Язык позволяет это делать, но это не значит, что так можно делать. Ведь язык позволяет делать и так
C++
1
2
int array[0];
array[100] = 123;
Kuzia domovenok
 Аватар для Kuzia domovenok
1883 / 1738 / 116
Регистрация: 25.03.2012
Сообщений: 5,907
Записей в блоге: 1
23.08.2013, 20:53     Исключение для чисто виртуальной функции #7
Цитата Сообщение от ArkTaS Посмотреть сообщение
и зачем это вообще делать, если эффект андефайнед ?
а зачем делить на ноль?
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,917
Записей в блоге: 2
Завершенные тесты: 1
23.08.2013, 20:58     Исключение для чисто виртуальной функции #8
Цитата Сообщение от ArkTaS Посмотреть сообщение
И в чем здесь проявляется полиморфизм имею ввиду косвенный вызов чистой вирт. функции ?
Зачем в 17 и 22 строке дважды писать virtual ? Как словить это исключение, какой тип писать ? и зачем это вообще делать, если эффект андефайнед ?
Ну если так скажете на собеседовании, то скорее всего "Вам перезвонят"
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
23.08.2013, 21:20  [ТС]     Исключение для чисто виртуальной функции #9
Цитата Сообщение от Croessmah Посмотреть сообщение
И в чем здесь проявляется полиморфизм имею ввиду косвенный вызов чистой вирт. функции ?
Зачем в 17 и 22 строке дважды писать virtual ? Как словить это исключение, какой тип писать ? и зачем это вообще делать, если эффект андефайнед ?
Ну если так скажете на собеседовании, то скорее всего "Вам перезвонят"
Кто нибудь объясните где здесь полиморфизм именно не вирт наследование, а "косвенный вызов чистой вирт. функции " ??
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
23.08.2013, 21:35     Исключение для чисто виртуальной функции #10
ArkTaS, Суть в том, что при вызове виртуальной функции из конструктора/деструктора будет вызван метод самого класса, а не потомка. В случае чисто-виртуальной функции это будет - произойдет что-то не то, что хотелось бы. Но при этом, здесь использована хитрость, которая мешает компилятору опознать вызов чисто-виртуальной функции из конструктора, ибо на самом деле вызов идет из функции класса, что является вполне нормальной практикой.
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
23.08.2013, 22:48     Исключение для чисто виртуальной функции #11
Сталкивался с таким несколько раз. Если вызов идет явно из конструктора, то это обычно отлавливается на этапе компиляции. Если вызов идет косвенно, через функции-члены, то уже только в рантайме. Разные реализации при попытке вызова чисто-виртуальной функции в той или иной форме выводят сообщение об этом "pure virtual function call".
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
24.08.2013, 01:40  [ТС]     Исключение для чисто виртуальной функции #12
Цитата Сообщение от ForEveR Посмотреть сообщение
ArkTaS, Суть в том, что при вызове виртуальной функции из конструктора/деструктора будет вызван метод самого класса, а не потомка. В случае чисто-виртуальной функции это будет - произойдет что-то не то, что хотелось бы. Но при этом, здесь использована хитрость, которая мешает компилятору опознать вызов чисто-виртуальной функции из конструктора, ибо на самом деле вызов идет из функции класса, что является вполне нормальной практикой.
А в какой ситуации будет вызван метод потомка (вирт.) из базового класса ? если таковой ситуации нет то это не может быть полиморфизмом ?!
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
24.08.2013, 02:45     Исключение для чисто виртуальной функции #13
ArkTaS, Если метод не будет вызван из конструктора/деструктора (прямо или косвенно).
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
 
class A
{
public:
   virtual ~A() {}
   void print()
   {
       print_impl();
   }
private:
    virtual void print_impl() = 0;
};
 
class B : public A
{
    void print_impl() { std::cout << "B" << std::endl; }
};
 
int main()
{
    A* b = new B();
    b->print();
}
https://ideone.com/uNrb5a
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
24.08.2013, 15:52  [ТС]     Исключение для чисто виртуальной функции #14
Цитата Сообщение от ForEveR Посмотреть сообщение
ArkTaS, Если метод не будет вызван из конструктора/деструктора (прямо или косвенно).
Читал Кернинга "Эфективное програмирование", Лафорте "ООП C++", больше понимания дал конечно Кернинг в вирт наследовании только вот как то в голове забилось что приватные члены не наследуются. После вашего приведенного кода, закралась мысль что где то я ошибся. Ну и практическим путем выяснилось что наследуются абсолютно все члены.
C++
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
#include <iostream>
 
class A
{
public:
    A(){std::cout << " Aconstr " << std::endl;}
   virtual ~A() {}
   void print()
   {
       print_impl();
   }
private:
     void print_impl() {std::cout << " A " << std::endl;}
};
 
class B : public A
{
public:
     B() {std::cout << " Bconstr " << std::endl;}
   // void print_impl() { std::cout << " B " << std::endl; }
};
 
class C : public B
{
public:
    C(){std::cout << " Cconstr " << std::endl;}
 
    //    void print_impl() { std::cout << " C " << std::endl; }
};
int main()
{
    C* b = new C();
    b->print();
    system("pause");
    std::cout<<std::endl;
}
ForEveR
Модератор
Эксперт C++
 Аватар для ForEveR
7927 / 4709 / 318
Регистрация: 24.06.2010
Сообщений: 10,524
Завершенные тесты: 3
25.08.2013, 02:48     Исключение для чисто виртуальной функции #15
ArkTaS, Наследуются все. Однако к приватным/защищенным нет доступа извне
IGPIGP
25.08.2013, 02:57
  #16

Не по теме:

Цитата Сообщение от ForEveR Посмотреть сообщение
Kuzia domovenok, Право, очень странно задавать такие вопросы, учитывая что мы пишем на языке UB++.
Я сначала не поверил, но архивы подтверждают...
На память UB'ивцам и душегUBам:

{
жуткая и правдивая история
о непреднамеренном вызове
чисто виртуального метода
из контейнера
полиморфных
указателей
}
=источник утерян=
***
Он всех в контейнер мрачный уложил
И рядом с каждым страшный указатель,
Как тайный знак грядущего проклятья,
Шепча заклятья спешно положил.

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

ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
25.08.2013, 23:33  [ТС]     Исключение для чисто виртуальной функции #17
Цитата Сообщение от ForEveR Посмотреть сообщение
ArkTaS, Наследуются все. Однако к приватным/защищенным нет доступа извне
Еще, хочу что бы вы оценили правильность моего восприятия виртуальности. В большинстве встречаемых мною источников сказано что выбор метода в случае если он не виртуальный соответствует типу указателя, если метод виртуальный то компилятор выбирает в зависимости от типа объекта на который указывает указатель. Вопросов может не возникнуть пока не дойдешь до изучения RTTI. Для себя я все представляю вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class base;
{
public:
    virtual void func() { cout<<endl<<" base func()"; } 
};
 
class derv: public base
{
public:
   virtual void func() { cout<<endl<<" derv func()";   } 
};
-||-
base* ptrB=new derv;
ptrB->func();
Компилятор связывает указатель ptrB с base частью derv объекта. Если бы была возможность выполнить команду ptrB->derv::func() компилятор выдал бы класс base не содержит члена derv::func(). Но время выполнения ptrB->func(); произойдет обращение к таблице виртуальных функций из которой будет выбрана соответствующая функция в зависимости от типа объекта. Выводы сделаны на основе реальной ошибки:
C++
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
#include <iostream>
 class A
{
public:
    A(){std::cout << " Aconstr " << std::endl;}
 
};
  
class C : public A
{
public:
 
    C(){std::cout << " Cconstr " << std::endl;}
 
    void func(){std::cout << " C fucn " << std::endl;}
 
};
int main()
{
    A* a = new C();
 
        a->func(); // Класс А не содержит члена func
    system("pause");
    std::cout<<std::endl;
}
В следующем коде компилятор обрезает объект класса derv и оставляет только его base часть и статически связывает вызов функции fucn() с объектом типа base.
C++
1
2
3
4
base B;
derv D;
B=D
B.func()
В отличии от предыдущего кода ситуацию с объектом (*ptrB) можно исправить и "вернуть ему его derv часть"
C++
1
2
3
4
5
.............................
base* ptrB=new derv;
ptrB->func();  
 
derv* ptrD=dynamic_cast<derv*>(ptrB)
Адрес перемещен из ptrB в ptrD и теперь он указывает на обе составляющие объекта.
Прошу уделить особое внимание выделенному жирным шрифтом.
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,917
Записей в блоге: 2
Завершенные тесты: 1
26.08.2013, 00:21     Исключение для чисто виртуальной функции #18
Наследование класс1 *test = new класс2
IGPIGP
Комп_Оратор)
 Аватар для IGPIGP
6172 / 2901 / 284
Регистрация: 04.12.2011
Сообщений: 7,720
Записей в блоге: 3
26.08.2013, 00:24     Исключение для чисто виртуальной функции #19
ArkTaS, если речь о указателях а не значениях, то усечения нет. Просто "слепо" указатель указывает на то на что указывает (в зависимости от типа его объявления). А доступ к виртуальным функциям через указатель базового класса это как исключение. Тем не менее если фактически он указывает на наследника и вы ему "раскроете глаза" приведением к типу этого наследника, то получите доступ. Потому, что фактически там оно есть.
Вот пример:
C++
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
#include <iostream>
using namespace std;
class A{
public:
int a;
A(int a_):a(a_){}
virtual void foo(){
cout<<"A.a= "<<a<<endl;
}
virtual void foo_to_ext(){}//мудро заготовили (так не бывает))
};
 
class B : public A
{
public:
int b;// расширение полем b
B(int a_, int b_) :A(a_), b(b_){}
virtual void foo(){
cout<<"B.a= "<<a<<endl;
}
virtual void foo_to_ext(){//к счастью завалялась ненужная v-func'ция :D
cout<<"B.b= "<<b<<endl;
}
};
int main()
{
 A* basePtr = new B( 1, 2);
basePtr->foo();
//cout<<basePtr->b; //это даже не компилируется 
//т.к. доступ только к V-functions, в остальном это указатель на А
 basePtr->foo_to_ext();//а это сработает: v-func'ция достала поле которого в A нет)
 
 
    system("pause");
    return 0;
}
Правда оба поля можно было и в первой foo достать, но может так понятнее.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.08.2013, 01:44     Исключение для чисто виртуальной функции
Еще ссылки по теме:

C++ В чем разница между виртуальной и чисто виртуальной функцией?
C++ Нужно ли прописывать конструктор и деструктор для чисто виртуального абстрактного класса
C++ Возможно ли? Базовый класс с чисто виртуальной функцией и наследники

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
26.08.2013, 01:44  [ТС]     Исключение для чисто виртуальной функции #20
Цитата Сообщение от IGPIGP Посмотреть сообщение
если речь о указателях а не значениях, то усечения нет. Просто "слепо" указатель указывает на то на что указывает (в зависимости от типа его объявления).
Если речь об указателях то я использовал термин "связывание" указателя с объектом, а если обращение через B=D то усечение, обрезание) я не прошу объяснять что будет если..... спасибо конечно за ваши старания. Можно слепо зазубрить весь особый синтаксис языка или сахар как называют его на лукморе и писать хорошие программы.
Мне нужно другое, я попытался человеческим понятным языком описать особенности полиморфизма в своей интерпретации. И мне интересно насколько она годна и имеет ли право на жизнь...Не возникнет ли в дальнейшем проблем при изучении, из за такого восприятия полиморфизма. Конкретно волнует выделенное жирним шрифтом:
Цитата Сообщение от ArkTaS Посмотреть сообщение
Если бы была возможность выполнить команду ptrB->derv::func() компилятор выдал бы класс base не содержит члена derv::func(). Но время выполнения ptrB->func(); произойдет обращение к таблице виртуальных функций из которой будет выбрана соответствующая функция в зависимости от типа объекта. Выводы сделаны на основе реальной ошибки:
C++
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
 
#include <iostream>
 class A
{
public:
    A(){std::cout << " Aconstr " << std::endl;}
 
};
  
class C : public A
{
public:
 
    C(){std::cout << " Cconstr " << std::endl;}
 
    void func(){std::cout << " C fucn " << std::endl;}
 
};
int main()
{
    A* a = new C();
 
        a->func(); // Класс А не содержит члена func
    system("pause");
    std::cout<<std::endl;
}
Добавлено через 4 минуты
Если бы была возможность выполнить команду ptrB->derv::func() компилятор выдал бы класс base не содержит члена derv::func(). Это правда ?
Yandex
Объявления
26.08.2013, 01:44     Исключение для чисто виртуальной функции
Ответ Создать тему
Опции темы

Текущее время: 21:58. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru