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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 42, средняя оценка - 4.64
Hardcore
4 / 4 / 0
Регистрация: 24.10.2010
Сообщений: 200
#1

Виртуальный методы, абстрактный класс. - C++

26.02.2012, 22:50. Просмотров 5701. Ответов 16
Метки нет (Все метки)

Здравствуйте.
Теоретические вопросы.
Что такое виртуальный методы и что такое абстрактный класс.
Можете объяснить своими словами без ссылок на википедию.
Заранее спасибо.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.02.2012, 22:50
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Виртуальный методы, абстрактный класс. (C++):

Виртуальный абстрактный класс - C++
Надеюсь мой вопрос будет не глупым. Есть класс исключений в пространстве имен std У него есть метод what Я создаю свой базовый класс...

Абстрактный класс. Виртуальный метод, который возвращает T- тип - C++
Привет! Допустим, есть абстрактный класс, и метод, который возвращает T-тип. class A { public: template <class T> T*...

Абстрактный класс «Клиент банка», имеющий виртуальный метод для вывода данных о клиенте - C++
Создать абстрактный класс «Клиент банка», имеющий поля ФИО и адрес, а также метод, для вывода данные по клиенту. Дочерними классами...

Абстрактный класс, виртуальные методы - C++
Учащийся: школьник, студент, аспирант. Каждый учащийся характеризуется: ФИО строки), дата рождения, пол (М/Ж). Школьник дополнительно...

абстрактный класс как реализовать данные, над которыми методы выполняют какие-либо действия - C++
Абстрактный класс как реализовать данные, над которыми методы выполняют какие-либо действия Задание: форматированный ввод и вывод...

Объясните как объявить абстрактный класс, и при этом не тащить виртуальные методы в производные классы - C++
Суть вопроса - есть у меня класс, который я решаю сделать абстрактным. Как я понимаю что бы сделать класс абстрактным необходимо просто...

16
_engineer_
116 / 73 / 2
Регистрация: 23.01.2012
Сообщений: 186
26.02.2012, 23:40 #2
Если несколько упрощать:
Абстрактный класс - Класс который описывает только прототипы функций без их реализации(в терминологии С++ интерфейс) , соответственно раз нет реализации не одного метода(функции), то нельзя создать экземпляр этого класса. Используется для того что бы все наследники этого класса имели не взирая, что они делают, единый интерфейс(вызов методов).
Виртуальный метод (функция) - Это такая функция которая переписана для каждого наследника класса. И определения какую функцию вызывать, программа будет решать не в момент написания кода, а в момент его выполнения. Допустим у вас три класcа:
B - базовый
N1 - наследник от B
N2 - наследник от B или N1
во всех трех классах есть виртуальная функция "V" которая в разных классах выполняет различные действия.
И есть в программе функция "f" которая в качестве аргумента получает указатель на базовый класс и имеет следущею реализацию В->V();
Теперь в эту функцию, Вы можете передать в качестве аргумента, класс B или N1 или N2 и будет выполнена функции V именно того класса который Вы передали.
Ну если коротенько, то гдето так.
2
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
27.02.2012, 23:55 #3
Цитата Сообщение от _engineer_ Посмотреть сообщение
Класс который описывает только прототипы функций без их реализации
Не обязательно. Чтобы быть абстрактным, класс должен содержать чистую виртуальную функцию. Из такого определения вытекает, что класс может содержать 100 обычных функцию с реализациями (даже не виртуальных) и одну чистую виртуальную, и тогда он будет абстрактным.

Цитата Сообщение от _engineer_ Посмотреть сообщение
(в терминологии С++ интерфейс)
В терминологии С++ как раз-таки нет понятия "интерфейсы". Так что это замена интерфейсам. С другой стороны, в таких языках, как Java и C# есть как интерфейсы, так и абстрактные классы.

Цитата Сообщение от _engineer_ Посмотреть сообщение
соответственно раз нет реализации не одного метода(функции), то нельзя создать экземпляр этого класса.
И снова - достаточно, чтобы не было реализации хотя бы одного метода (он должен быть объявлен как чисто виртуальный - virtual type method(parameters) = 0;), то нельзя создать объект такого класса, потому что он становится абстрактным. Независимо от реализаций и виртуальности остальных его методов.

Цитата Сообщение от _engineer_ Посмотреть сообщение
Это такая функция которая переписана для каждого наследника класса
Не обязательно. Класс-наследник может безболезненно использовать реализацию класса-родителя.
Виртуальный метод - это метод, конкретная реализация которого определяется во время исполнения программы на основании типа объекта, из которого был вызван метод.
1
akk
44 / 44 / 7
Регистрация: 28.01.2012
Сообщений: 341
22.05.2013, 00:52 #4
А у меня есть такой вопрос по абстрактным классам и виртуальным функциям.
Если в абстрактном классе, к примеру 2 виртуальные функции (не важно чисто виртуальные или нет), то в производном классе не могут же существовать другие методы, кроме этих 2-х переопределенных? Точнее они могут существовать, но если что-то типа такого
C++
1
2
BaseClass * pointer = new ChildClass();
pointer->SobstvenniyChaildMetodKotorogoNetVBase();
то компилятор ругается, что нету такой функции.
0
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.05.2013, 12:16 #5
Цитата Сообщение от akk Посмотреть сообщение
то компилятор ругается, что нету такой функции.
Разумеется. Родитель ничего не знает о дополнениях, добавленных в наследнике, в том числе о новых методах. А раз этого не знает родитель, то этого не знает и компилятор, поэтому в случае попытки вызова метода, появившегося только в потомке, компилятор скажет, что такого метода в предке не существует. С тем же успехом можно попытаться вызвать через указатель на наследника метод, которого вообще нет ни в одном классе программы.
1
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
22.05.2013, 12:54 #6
Цитата Сообщение от akk Посмотреть сообщение
то компилятор ругается, что нету такой функции.
Если нужно вызвать метод дочернего класса (которого не было в базовом), имея только указатель базового типа, то можно использовать приведение типа:
C++
1
2
BaseClass * pointer = new ChildClass();
dynamic_cast<ChildClass*>(pointer)->SobstvenniyChaildMetodKotorogoNetVBase();
По-хорошему, еще не помешает проверка после приведения.
1
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.05.2013, 13:17 #7
Цитата Сообщение от Tulosba Посмотреть сообщение
то можно использовать приведение типа
Да, этот способ имеет место быть. Но зачастую его применение говорит об изначальной непродуманности самой архитектуры.

Цитата Сообщение от Tulosba Посмотреть сообщение
По-хорошему, еще не помешает проверка после приведения.
А вот это надо делать не "по-хорошему", а всегда.
0
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
22.05.2013, 13:24 #8
Цитата Сообщение от silent_1991 Посмотреть сообщение
А вот это надо делать не "по-хорошему", а всегда.
В данном случае из 2х строк даже не представляю, что должно произойти, чтобы pointer не привелся к типу ChildClass*, т.е. вернул nullptr.
0
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.05.2013, 13:28 #9
Цитата Сообщение от Tulosba Посмотреть сообщение
В данном случае из 2х строк даже не представляю, что должно произойти, чтобы pointer не привелся к типу ChildClass*, т.е. вернул nullptr.
Если в данном случае используется такой подход, то проблема не в архитектуре, а в голове автора (к вам, разумеется, не относится, ибо это пример). Не могу представить себе ситуацию, когда на одной странице кода было бы видно создание объекта дочернего класса, присваивание его адреса ссылке/указателю на базовый класс, и приведение этой ссылки/указателя к ссылку/указателю на дочерний класс. Но, в любом случае, я бы всё равно сделал проверку. Код имеет свойство разрастаться, при этом и посредством вклинивания новых строк между существующими.
0
akk
44 / 44 / 7
Регистрация: 28.01.2012
Сообщений: 341
22.05.2013, 19:34 #10
А если делать проверку то у меня работает только так:
C++
1
2
3
4
if (pointer[i]=dynamic_cast<ClassChild*>(pointer[i]))
 {
dynamic_cast<ClassChild*>(goods[i])->GetMetodChild(); 
}
Всегда нужно получается приводит, т е перед каждым методом писать dynamic_cast<ClassChild*>(goods[i])->GetMetodChild(); то есть у меня почему-то в if не получается такое присваивания или так и должно быть.
0
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.05.2013, 19:38 #11
akk, потому что pointer[i] имеет тип ClassBase *, к которому во время присваивания автоматически приводится указатель, полученный после dynamic_cast. Делать надо так:
C++
1
2
3
ClassChild *cc_ptr = dynamic_cast<ClassChild *>(pointer[i]);
if (cc_ptr)
    cc_ptr->GetMethodChild();
Добавлено через 1 минуту
А вообще, какое отношение проверяемый pointer[i] имеет к goods[i], из которого вызывается метод? Если вызываете из goods[i], то и проверять надо именно его.
1
akk
44 / 44 / 7
Регистрация: 28.01.2012
Сообщений: 341
22.05.2013, 19:40 #12
silent_1991, т е надо использовать другой временный указатель подкласса, и под ним выполнять методы? Но так данные не потеряются?
0
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.05.2013, 19:40 #13
akk, а куда они потеряются-то? Это же указатель, а не копия объекта.
0
akk
44 / 44 / 7
Регистрация: 28.01.2012
Сообщений: 341
22.05.2013, 19:54 #14
Цитата Сообщение от silent_1991 Посмотреть сообщение
Это же указатель, а не копия объекта.
Ну так если память выделяется динамически, а потом происходит приведения к другому типу, и заполняется методами подкласса?

Добавлено через 9 минут
И если к примеру имеется еще один указатель базового класса, то можно сделать просто так или тоже надо приводить.

C++
1
2
3
4
5
6
7
8
9
10
Base * pointer1, * pointer2;
pointer1 = new ChildClass();
ChildClass * ptr = dynamic_cast<ChildClass *>(pointer1);
if(ptr)
    //заполняем данными класс
 
pointer2=pointer1;
ChildClass * p = dynamic_cast<ChildClass *>(pointer2);
if(p)
//просматриваем к примеру введенные данные
т е безбоязненно такое присваивание будет pointer2=pointer1 ?
0
silent_1991
Эксперт С++
4987 / 3044 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
22.05.2013, 20:10 #15
akk, вам бы подучить основы, а потом уже приступать к полиморфизму. Никакая память никакими методами не заполняется. Вы полагаете, что каждый объект хранить все методы своего класса? Это неверно. Методы в программе располагаются в единственном экземпляре. Полиморфизм работает благодаря тому, что каждый объект хранит ссылку на таблицу виртуальных методов своего класса. Т.е. в vtable объекта типа ChildClass есть указатели на все виртуальные методы ChildClass, в том числе на те, которых нет в BaseClass. Но если адрес этого объекта присвоен указателю на BaseClass, компилятор просто не знает, что по этому указателю на самом деле лежит объект типа ClassChild с расширенной по отношению к BaseClass таблицей виртуальных методов. Приведение вниз посредством dynamic_cast заставляет компилятор понять, что на самом деле используется vtable класса ChildClass, и позволить нам вызвать методы, добавленные в этом классе.

Код вашего примера не понял, как и вопроса касательно него. В данном случае pointer1 и pointer2 в конечном счёте будут указывать на один и тот же объект типа ChildClass. Если хотите вызывать методы, добавленные в ChildClass, как через pointer1, так и через pointer2 - надо делать приведение вниз.

Добавлено через 6 минут
Цитата Сообщение от silent_1991 Посмотреть сообщение
Приведение вниз посредством dynamic_cast заставляет компилятор понять, что на самом деле используется vtable класса ChildClass, и позволить нам вызвать методы, добавленные в этом классе.
Вернее сказать даже не так. dynamic_cast играет роль только во время выполнения. Компилятору наплевать на vtable, ему важно, чтобы тип указателя, через который вызывается метод, содержал этот вызываемый метод.
1
22.05.2013, 20:10
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.05.2013, 20:10
Привет! Вот еще темы с ответами:

Опишите абстрактный базовый класс "строка",реализующий методы ввода-вывода строки - C++
Кто поможет,тому магарыч. Опишите абстрактный базовый класс &quot;строка&quot;,реализующий методы ввода-вывода строки. Производный класс дает свою...

Создать класс Triad (тройка чисел) - определить методы; определить производный класс Date - переопределить методы - C++
Создать класс Triad (тройка чисел); определить методы увеличения полей на 1. Определить производный класс Date с полями: год, месяц и день....

Класс: Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра. - C++
Создать абстрактный базовый класс Figure с виртуальными методами вычисления площади и периметра. Создать производные классы: Rectangle...

Абстрактный класс, наследование, класс хранится в другом классе - C++
Нужна помощь. Написать программу: 1 класс. Имеется абстрактный класс который описывает какую-то сущность, например Человек. В абстрактном...


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

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

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