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

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

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 42, средняя оценка - 4.64
Hardcore
4 / 4 / 0
Регистрация: 24.10.2010
Сообщений: 200
26.02.2012, 22:50     Виртуальный методы, абстрактный класс. #1
Здравствуйте.
Теоретические вопросы.
Что такое виртуальный методы и что такое абстрактный класс.
Можете объяснить своими словами без ссылок на википедию.
Заранее спасибо.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.02.2012, 22:50     Виртуальный методы, абстрактный класс.
Посмотрите здесь:

C++ Разработать классы для описанных ниже объектов. Включить в класс методы set (…), get (…), show (…). Определить другие методы
Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ... C++
абстрактный класс как реализовать данные, над которыми методы выполняют какие-либо действия C++
C++ Создать класс Triad (тройка чисел) - определить методы; определить производный класс Date - переопределить методы
C++ Создать абстрактный базовый класс Тройка чисел с виртуальными методами увеличения на 1. Создать производный класс Время со своими функциями
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
_engineer_
115 / 72 / 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 именно того класса который Вы передали.
Ну если коротенько, то гдето так.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
27.02.2012, 23:55     Виртуальный методы, абстрактный класс. #3
Цитата Сообщение от _engineer_ Посмотреть сообщение
Класс который описывает только прототипы функций без их реализации
Не обязательно. Чтобы быть абстрактным, класс должен содержать чистую виртуальную функцию. Из такого определения вытекает, что класс может содержать 100 обычных функцию с реализациями (даже не виртуальных) и одну чистую виртуальную, и тогда он будет абстрактным.

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

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

Цитата Сообщение от _engineer_ Посмотреть сообщение
Это такая функция которая переписана для каждого наследника класса
Не обязательно. Класс-наследник может безболезненно использовать реализацию класса-родителя.
Виртуальный метод - это метод, конкретная реализация которого определяется во время исполнения программы на основании типа объекта, из которого был вызван метод.
akk
 Аватар для 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();
то компилятор ругается, что нету такой функции.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
22.05.2013, 12:16     Виртуальный методы, абстрактный класс. #5
Цитата Сообщение от akk Посмотреть сообщение
то компилятор ругается, что нету такой функции.
Разумеется. Родитель ничего не знает о дополнениях, добавленных в наследнике, в том числе о новых методах. А раз этого не знает родитель, то этого не знает и компилятор, поэтому в случае попытки вызова метода, появившегося только в потомке, компилятор скажет, что такого метода в предке не существует. С тем же успехом можно попытаться вызвать через указатель на наследника метод, которого вообще нет ни в одном классе программы.
Tulosba
:)
Эксперт C++
4377 / 3220 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
22.05.2013, 12:54     Виртуальный методы, абстрактный класс. #6
Цитата Сообщение от akk Посмотреть сообщение
то компилятор ругается, что нету такой функции.
Если нужно вызвать метод дочернего класса (которого не было в базовом), имея только указатель базового типа, то можно использовать приведение типа:
C++
1
2
BaseClass * pointer = new ChildClass();
dynamic_cast<ChildClass*>(pointer)->SobstvenniyChaildMetodKotorogoNetVBase();
По-хорошему, еще не помешает проверка после приведения.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
22.05.2013, 13:17     Виртуальный методы, абстрактный класс. #7
Цитата Сообщение от Tulosba Посмотреть сообщение
то можно использовать приведение типа
Да, этот способ имеет место быть. Но зачастую его применение говорит об изначальной непродуманности самой архитектуры.

Цитата Сообщение от Tulosba Посмотреть сообщение
По-хорошему, еще не помешает проверка после приведения.
А вот это надо делать не "по-хорошему", а всегда.
Tulosba
:)
Эксперт C++
4377 / 3220 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
22.05.2013, 13:24     Виртуальный методы, абстрактный класс. #8
Цитата Сообщение от silent_1991 Посмотреть сообщение
А вот это надо делать не "по-хорошему", а всегда.
В данном случае из 2х строк даже не представляю, что должно произойти, чтобы pointer не привелся к типу ChildClass*, т.е. вернул nullptr.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
22.05.2013, 13:28     Виртуальный методы, абстрактный класс. #9
Цитата Сообщение от Tulosba Посмотреть сообщение
В данном случае из 2х строк даже не представляю, что должно произойти, чтобы pointer не привелся к типу ChildClass*, т.е. вернул nullptr.
Если в данном случае используется такой подход, то проблема не в архитектуре, а в голове автора (к вам, разумеется, не относится, ибо это пример). Не могу представить себе ситуацию, когда на одной странице кода было бы видно создание объекта дочернего класса, присваивание его адреса ссылке/указателю на базовый класс, и приведение этой ссылки/указателя к ссылку/указателю на дочерний класс. Но, в любом случае, я бы всё равно сделал проверку. Код имеет свойство разрастаться, при этом и посредством вклинивания новых строк между существующими.
akk
 Аватар для 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 не получается такое присваивания или так и должно быть.
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 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], то и проверять надо именно его.
akk
 Аватар для akk
44 / 44 / 7
Регистрация: 28.01.2012
Сообщений: 341
22.05.2013, 19:40     Виртуальный методы, абстрактный класс. #12
silent_1991, т е надо использовать другой временный указатель подкласса, и под ним выполнять методы? Но так данные не потеряются?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
22.05.2013, 19:40     Виртуальный методы, абстрактный класс. #13
akk, а куда они потеряются-то? Это же указатель, а не копия объекта.
akk
 Аватар для 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 ?
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 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, ему важно, чтобы тип указателя, через который вызывается метод, содержал этот вызываемый метод.
akk
 Аватар для akk
44 / 44 / 7
Регистрация: 28.01.2012
Сообщений: 341
22.05.2013, 20:14     Виртуальный методы, абстрактный класс. #16
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Base * pointer1, * pointer2;
pointer1 = new ChildClass();
ChildClass * ptr = dynamic_cast<ChildClass *>(pointer1);
if(ptr)
    ptr->GetMetod();
//... 
pointer2=pointer1;
pointer1=NULL;
//...
ptr = dynamic_cast<ChildClass *>(pointer2);
if(ptr)
    ptr->GetMetod(); //тоже самое что и выше
//...
delete pointer2;
Так можно делать?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
22.05.2013, 20:16     Виртуальный методы, абстрактный класс.
Еще ссылки по теме:

C++ Опишите абстрактный базовый класс "строка",реализующий методы ввода-вывода строки
C++ Абстрактный класс. Виртуальный метод, который возвращает T- тип
Абстрактный класс, виртуальные методы C++

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

Или воспользуйтесь поиском по форуму:
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
22.05.2013, 20:16     Виртуальный методы, абстрактный класс. #17
Цитата Сообщение от akk Посмотреть сообщение
Так можно делать?
За исключением того, что в строках 3 и 10 нужно использовать разные имена, да, не вижу препятствий сделать так (как не вижу и того, что вас смущает в этом коде).
Yandex
Объявления
22.05.2013, 20:16     Виртуальный методы, абстрактный класс.
Ответ Создать тему
Опции темы

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