| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > абстрактный класс |
| Автор: mrgloom 17.5.2013, 15:26 | ||
| Почему нельзя создать объект абстрактного класса? но можно создать на него указатель. (непонятно именно с логической точки зрения). потому что создав указатель всё равно можно навредить
|
| Автор: mes 17.5.2013, 15:36 |
mrgloom, указатель не создают... навредить можно еше тысячей разных способов.. при этом, что указанный вред никак не связан с абстрактным классом.. и.. "не навреди" единным жив программист.... |
| Автор: Arantir 17.5.2013, 15:53 | ||
Можно создать указатель, в который можно поместить объект, наследующий этот класс. Это просто будет значить, что объект в указателе (точнее, на который этот указатель указывает) обязательно должен быть наследником этого абстрактного класса. В других языках для этого существуют еще и интерфейсы.
Программиста от собственного ума ничего не спасет. |
| Автор: mrgloom 20.5.2013, 12:40 | ||||||
объявляют? т.е. как бы создание класса предполагает собой создание чего(выделение памяти), а указатель просто указатель на такой то тип? но так же можно было бы и создать "пустой" класс, где какое то поле не опеределено или какой то метод. так что непонятно такое ограничение.
ну имхо это интуитивно\логически неправильно, хотя понятно что это "фича" языка. Добавлено через 2 минуты и 41 секунду хотя опять же есть static функции которыми можно пользоваться без создания класса. Добавлено через 5 минут и 43 секунды но вопрос то не в этом, а в том почему нельзя определить класс с абстрактным методом. Добавлено через 7 минут и 14 секунд
|
| Автор: Guinness 20.5.2013, 12:52 | ||
Если я ничего не путаю, то это не фича языка. При компиляции обычные функции класса компилируются в определенный раздел exe-шника. И для любового экзепляра класса будут вызываться функции хранящиеся в одной области памяти. (Может быть ошибаюсь, но мне когда-то так объясняли работу вышеуказанного кода). К слову этот код должен ломаться, если сделать данную функцию объявить виртуальной. Т.к. для каждого экземпляра класса создается своя таблица виртульных функций. |
| Автор: xvr 20.5.2013, 13:08 | ||
Потому и нельзя - метода то нет |
| Автор: Arantir 20.5.2013, 13:17 | ||
Ага, называется NULL. Дело в том, что это логическая бомба. Если метод имеет тип возвращаемого значения, то программа ожидает это значение в 100% вызовов этого метода. Вызывать абстрактный метод априори не имеет смысла. Если вам нужно создавать экземпляр класса, зачем его вообще делать абстрактным? То, что вам нужно, можно и нужно реализовывать своими руками. Если вам нужны пустые методы для переопределения в наследниках, то для этого существуют виртуальные методы:
переопределенные в дочернем классе, они заменят родительский метод даже, если указатель будет иметь тип родительского. В то же время можно создать экземпляр родительского класса. А при потребности можно выбросить исключение при вызове не переопределенного метода. Абстрактный класс предназначен именно для случая, когда его экземпляр не должен создаваться по замыслу разработчика. Кроме того, в C++ абстрактный класс так же может являться и интерфейсом. Это значит, что разработчик требует, чтобы в задуманных местах объекты в любом случае имели предусмотренные поля и методы. При этом класс, описывающих набор этих методов, является лишь шаблоном (такой себе инструкцией) и заведомо не нуждается в создании своих экземпляров. |
| Автор: volatile 20.5.2013, 13:48 | ||
Нельзя и всё! Воспринимайте как данность. Вообще, сделано для удобства программиста. Например, если в наследнике вы забудете определить какой-то абстрактный метод, то компилятор вам об этом ненавязчиво напомнит. |
| Автор: mrgloom 20.5.2013, 16:31 | ||||||||||||||||||
| Так получается я всегда предполагается использовать только производный класс? т.е. не
а
http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr142.htm так зачем мне может понадобиться ссылка на базовый класс?или в 1 месте я могу унаследовать 1 метод, в другом другой типа
еще вопрос с примером
зачем нужна ссылка на базовый клас в производном классе?
в BestOf2NearestMatcher::match первой строчкой вызывается оператор ()
в переопределенном операторе
и match используется уже от BestOf2NearestMatcher? причем мы нигде не указали, что impl_ должен использовать BestOf2NearestMatcher::match. + получается что BestOf2NearestMatcher::match внутри BestOf2NearestMatcher::match и рекурсия?(вообщем этот момент непонятен) и что делает ?
|
| Автор: Arantir 20.5.2013, 18:16 | ||
mrgloom, Ваша проблема в том, что Вы рассматриваете программу, как http://ru.wikipedia.org/wiki/%D0%A7%D1%91%D1%80%D0%BD%D1%8B%D0%B9_%D1%8F%D1%89%D0%B8%D0%BA. Попробуйте начать рассматривать ее как http://en.wikipedia.org/wiki/White_box_(software_engineering).
Вы сами решаете, что предполагается использовать. И на основе этого создаете структуру программы. если предполагается любой класс с неким методом, то вы делаете указатель на абстрактный класс с этим методом. если предполагается конкретный Вами же написанный класс, то абстрактный класс для него не нужен. Почитайте про фреймворки... Абстрактные классы весьма полезны, если предполагается, что ваш код — только каркас, и тот, кто его использует, часть функционала будет реализовать самостоятельно в виде собственных классов. Чтобы фреймворк мог эти классы использовать, то и используются указатели с типом абстрактного класса. В такой указатель может быть помещен объект класса, созданного пользователем фреймворка. |
| Автор: bsa 21.5.2013, 11:13 |
| mrgloom, очень сложные программы пишутся в виде модулей. Так удобнее писать и проще обслуживать. Возьмем для примера ядро Linux. Оно хоть и на С написано, но ООП там используется в полный рост. Есть в нем некая подсистема. Устройств этого типа может быть куча, поэтому сразу же делается интерфейс для драйвера. Допустим, у драйвера должно быть 3 метода (ioctl, read, write). Вот разработчик подсистемы и делает класс с 3-мя чисто виртуальными функциями. Вся подсистема работает и взаимодействует с устройством через этот интерфейс. Затем другой разработчик решил написать драйвер для устройства Х. Он пишет наследника класса-интерфейса и переопределяет эти методы. Теперь, подсовывая объект драйвера, подсистема начинает работать полноценно. |
| Автор: xvr 21.5.2013, 11:22 | ||
Это не ссылка на базовый класс - это ссылка на реализацию самого BestOf2NearestMatcher, причем она [реализация] находится не в родителе класса, а задается где то отдельно, снаружи. Это классическая реализация паттерна http://insidecpp.ru/patterns/pimpl_idiom/
Нет. Эти match вызываются от разных объектов |
| Автор: mrgloom 21.5.2013, 12:13 | ||||||
всё таки я не понял.
откуда берется match? я так понимаю, что если
то match должна быть определена в классе наследнике, собственно говоря BestOf2NearestMatcher::match но в ней первая же строчка непонятно для чего служит.
impl_ как я понял нужно для того чтобы можно был овызывать функции из класса FeaturesMatcher, хотя зачем это нужно если мы и так от него унаследовались. |
| Автор: xvr 21.5.2013, 12:53 | ||||
Именно так А вот это и есть вызов реализации. impl_ здесь смотрит не на родителя, а на другой экземпляр наследника FeaturesMatcher
Мы не себя вызываем, а другого наследника. Класс FeaturesMatcher (и его наследники, в частности BestOf2NearestMatcher) описывают единственный тип, а вот экземпляров этих типов (т.е. непостредственно объектов) может быть созданно много. И при вызове метода происходит вызов именно от экземпляра объекта, а не от самого класса/типа. |
| Автор: mrgloom 21.5.2013, 14:22 | ||
| всё понял, в конструкторе BestOf2NearestMatcher как раз выбирался наследник. в cpp определены CpuMatcher : public FeaturesMatcher GpuMatcher : public FeaturesMatcher и имеют CpuMatcher::match GpuMatcher::match
|