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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 13, средняя оценка - 4.62
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
#1

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

23.08.2013, 18:45. Просмотров 1865. Ответов 21
Метки нет (Все метки)

Читал вопросы на собеседованиях по С++ и столкнулся с 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 генерировавшего некое исключение, ни объявления исключений
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.08.2013, 18:45
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Исключение для чисто виртуальной функции (C++):

НЕнаследование чисто виртуальной функции - C++
Доброго времени суток ! Есть абстрактный класс A с одной чисто виртуальной функцией. Есть два наследуемых класса В и С, которым...

В чем разница между виртуальной и чисто виртуальной функцией? - C++
в чем разница между виртуальной и чисто виртуальной функцией? virtual void print(){..} virtual void ex(..)=0;

Возможно ли? Базовый класс с чисто виртуальной функцией и наследники - C++
есть такая ситуация, есть базовый класс и от него 2 наследника. У наследников есть одинаковые функции, но имеющие разный тип принимаемого...

Указатель для вызова виртуальной функции - C++
Помогите разобраться в строении вызова виртуальной функции Если не сложно, объсните каждый указатель #include <iostream> ...

Чисто вирутальные функции в шаблонном классе - C++
Хотелось бы узнать, поддерживает ли это свойство Visual C++ 2010.

Вызвано исключение: нарушение доступа для чтения. Функции и двумерные массивы - C++
Здравствуйте. В процессе выполнения несложного учебного задания столкнулся с ошибкой. Подозреваю, что ошибка очень глупая и вызвана...

21
IGPIGP
25.08.2013, 02:57     Исключение для чисто виртуальной функции
  #16

Не по теме:

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

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

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

2
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 и теперь он указывает на обе составляющие объекта.
Прошу уделить особое внимание выделенному жирным шрифтом.
0
Croessmah
Эксперт CЭксперт С++
13510 / 7668 / 866
Регистрация: 27.09.2012
Сообщений: 18,865
Записей в блоге: 3
Завершенные тесты: 1
26.08.2013, 00:21 #18
Наследование класс1 *test = new класс2
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
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 достать, но может так понятнее.
1
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(). Это правда ?
0
IGPIGP
Комп_Оратор)
Эксперт по математике/физике
6503 / 3139 / 307
Регистрация: 04.12.2011
Сообщений: 8,661
Записей в блоге: 5
26.08.2013, 02:22 #21
Цитата Сообщение от ArkTaS Посмотреть сообщение
. Если бы была возможность выполнить команду ptrB->derv::func() компилятор выдал бы класс base не содержит члена derv::func().
ptB-> это обращение к члену класса base, так как ptB обявлен как base *, - указатель на объект типа base. В base нет имени derv. Это в принципе не относится к наследованию и полиморфизму при наследовании.
derv это отдельный класс. Хоть и наследник. Область его видимости не входит в базовый класс. Другими словами, базовый класс о нём ничего не знает. То что к его виртуальному методу можно обратиться через указатель на base, используя синтаксис обращения к его собственной виртуальной функции, это свойство языка. Ни к каким невиртуальным функциям и полям которых у base нет, так обратиться нельзя. Даже если base, наделе содержит адрес объекта производного класса, то указатель этого не видит. Иначе говоря, если его привести к типу derv, то тогда уже вычесленное выражение (derv*)ptrB будет интерпретироваться "указатель на derv", то есть "тот который видит члены derv". Ну и сами виртуальные функции могут позволить получить доступ к переменным наследника, если они так переопределены. Чтобы это было легче, пересмотрите доступ к членам структур и классов через указатель. Иначе никак точно не скажете, хотя интуитивно верно пытаетесь выразить.
1
ArkTaS
1 / 1 / 0
Регистрация: 01.07.2013
Сообщений: 127
26.08.2013, 19:27  [ТС] #22
Цитата Сообщение от IGPIGP Посмотреть сообщение
Чтобы это было легче, пересмотрите доступ к членам структур и классов через указатель. Иначе никак точно не скажете, хотя интуитивно верно пытаетесь выразить.
Цитата Сообщение от IGPIGP Посмотреть сообщение
Если бы была возможность выполнить команду ptrB->derv::func() компилятор выдал бы класс base не содержит члена derv::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
27
28
29
30
31
#include <iostream>
#include <typeinfo> // для dynamic_cast
using namespace std;
 
class Base
{
public:
    virtual void show() { cout<<endl<<" Base show "; }
 
};
 
class Derv: public Base
{
public:
    virtual void show(){ cout<<endl<<" Derv show ";  }
};
 
int main()
{
    setlocale( LC_ALL,"Russian" );
    
    Base *ptr_base=new Derv();
 
    void (Derv::*ptr_Derv_show) ()=&Derv::show;
    ((*ptr_base).*ptr_Derv_show)();    // Ошибка преобразования и невозможно передать ссылку .... 
 
 
    cout<<endl;
    system("pause");
    return 0;
}
Добавлено через 6 минут
IGPIGP,
C++
1
2
3
4
    void (Base::*ptr_Base_show) ()=&Base::show;
    ((*ptr_base).*ptr_Base_show)();   // Обращение к таблице виртуальных функций 
        //для выбора подходящего метода через указатель на base, 
        //используя синтаксис обращения к его собственной виртуальной функции
0
26.08.2013, 19:27
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.08.2013, 19:27
Привет! Вот еще темы с ответами:

Компилятор С++ для генерации чисто двоичного формата - C++
Подскажите сабж. Нужно для написания ядра микро-операционки

Нужно ли прописывать конструктор и деструктор для чисто виртуального абстрактного класса - C++
Всем привет! Порылся в интернете, но не смог найти конкретного ответа на свой вопрос. Возможно я просто не смог грамотно сформулировать...

Смысл виртуальной функции? - C++
Добрый день, вопрос состоит в следующем, какой вообще смысл иметь виртуальную функцию? ну точней, вот если можно какой нибудь маленький...

Переопределение виртуальной функции - C++
Всем доброй ночи :) Есть базовый абстрактный класс и два производных класса (А и В), в которых я пытяюсь переопределить виртуальную...


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

Или воспользуйтесь поиском по форуму:
22
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru