Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> абстрактный класс 
:(
    Опции темы
mrgloom
Дата 17.5.2013, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



Почему нельзя создать объект абстрактного класса? но можно создать на него указатель.
(непонятно именно с логической точки зрения).

потому что создав указатель всё равно можно навредить

Код

Ptr<AbstractClass> cl;
//cl= new ClassWithMethod(); // если не сделать этого
cl->domethod(); // падает 


Это сообщение отредактировал(а) mrgloom - 17.5.2013, 15:29
PM MAIL   Вверх
mes
Дата 17.5.2013, 15:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(mrgloom @  17.5.2013,  14:26 Найти цитируемый пост)
но можно создать на него указатель

mrgloom, указатель не создают... 

Цитата(mrgloom @  17.5.2013,  14:26 Найти цитируемый пост)
всё равно можно навредить

навредить можно еше тысячей разных способов.. при этом, что указанный вред никак не связан с абстрактным классом..

и.. "не навреди" единным жив программист.... 



Это сообщение отредактировал(а) mes - 19.5.2013, 09:39


--------------------
PM MAIL WWW   Вверх
Arantir
Дата 17.5.2013, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Рыбак без удочки
**


Профиль
Группа: Участник
Сообщений: 960
Регистрация: 18.11.2012

Репутация: 1
Всего: 55



Цитата(mrgloom @  17.5.2013,  14:26 Найти цитируемый пост)
но можно создать на него указатель.

Можно создать указатель, в который можно поместить объект, наследующий этот класс. Это просто будет значить, что объект в указателе (точнее, на который этот указатель указывает) обязательно должен быть наследником этого абстрактного класса.
В других языках для этого существуют еще и интерфейсы.


Цитата(mrgloom @  17.5.2013,  14:26 Найти цитируемый пост)
всё равно можно навредить

Код

Ptr<AbstractClass> cl;
//cl= new ClassWithMethod(); // если не сделать этого
vgj$#!#^^@%T(@*#& // падает 

Программиста от собственного ума ничего не спасет.

Это сообщение отредактировал(а) Arantir - 17.5.2013, 15:55


--------------------
interface Жопа {
    // ATTENTION: has to be implemented by every class of the project for proper project work
}
PM   Вверх
NoviceF
Дата 17.5.2013, 16:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 313
Регистрация: 13.3.2012
Где: Ростов-на-Дону

Репутация: нет
Всего: 2



Цитата(mrgloom @  17.5.2013,  16:26 Найти цитируемый пост)
Почему нельзя создать объект абстрактного класса? но можно создать на него указатель.

как уже в общем написали выше, через указатель на базовый класс можно обращаться к наследникам этого базового класса, это называется динамический полиморфизм.


Цитата(mrgloom @  17.5.2013,  16:26 Найти цитируемый пост)
потому что создав указатель всё равно можно навредить

вот тебе ещё на тему smile

Код

class ABC{
public:
        int a;
        void print(){cout<<"hello"<<endl;}
};

int main(){
        ABC *ptr = NULL:
        ptr->print();
        return 0;
}

http://stackoverflow.com/questions/2505328...l-class-pointer

тоже всё будет работать, пока нет обращения к членам данным. То есть можно забыть создать или проинициализировать член данное в классе (если обращение к нему происхоодит через указатель), а потом появятся загадочные падения в конструкторе копирования, например smile

Код

class ABC{
public:
    int a;
    void print(){cout<<"hello"<<endl;}

    int GetX() { return *x; }

private:
    int* x;
};
    

 int main()
 {
    ABC *ptr = NULL; 
    ptr->print();           // ok (ну как ок.. вообще-то это уб, но программа не упадёт)
    ptr->GetX();           // а вот тут упадёт

    return 0;
 }


про указатель это так.. из практики smile а в данном премере достаточно попробовать обратиться к
Код

int a;



Это сообщение отредактировал(а) NoviceF - 17.5.2013, 16:57
PM MAIL   Вверх
mrgloom
Дата 20.5.2013, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



Цитата

mrgloom, указатель не создают... 

объявляют? 
т.е. как бы создание класса предполагает собой создание чего(выделение памяти), а указатель просто указатель на такой то тип?
но так же можно было бы и создать "пустой" класс, где какое то поле не опеределено или какой то метод.
так что непонятно такое ограничение. 

Цитата

class ABC{
public:
        int a;
        void print(){cout<<"hello"<<endl;}
};
int main(){
        ABC *ptr = NULL:
        ptr->print();
        return 0;
}

ну имхо это интуитивно\логически неправильно, хотя понятно что это "фича" языка.

Добавлено через 2 минуты и 41 секунду
хотя опять же есть static функции которыми можно пользоваться без создания класса.

Добавлено через 5 минут и 43 секунды
но вопрос то не в этом, а в том почему нельзя определить класс с абстрактным методом.

Добавлено через 7 минут и 14 секунд
Код

AbstractClass cl;
cl.domethod(); // путь тут так же и упадёт

PM MAIL   Вверх
Guinness
Дата 20.5.2013, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 310
Регистрация: 21.6.2009
Где: Зеленоград

Репутация: нет
Всего: 10



Цитата(mrgloom @  20.5.2013,  12:40 Найти цитируемый пост)
ну имхо это интуитивно\логически неправильно, хотя понятно что это "фича" языка.

Если я ничего не путаю, то это не фича языка. При компиляции обычные функции класса компилируются в определенный раздел exe-шника. И для любового экзепляра класса будут вызываться функции хранящиеся в одной области памяти. (Может быть ошибаюсь, но мне когда-то так объясняли работу вышеуказанного кода).
К слову этот код должен ломаться, если сделать данную функцию объявить виртуальной. Т.к. для каждого экземпляра класса создается своя таблица виртульных функций.
PM MAIL   Вверх
xvr
Дата 20.5.2013, 13:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mrgloom @  20.5.2013,  12:40 Найти цитируемый пост)
но вопрос то не в этом, а в том почему нельзя определить класс с абстрактным методом.

Потому и нельзя - метода то нет  smile Есть только заглушка, которая никогда не должна вызываться, поэтому и экземпляр такого класса создать нельзя.

PM MAIL   Вверх
Arantir
Дата 20.5.2013, 13:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Рыбак без удочки
**


Профиль
Группа: Участник
Сообщений: 960
Регистрация: 18.11.2012

Репутация: 1
Всего: 55



Цитата(mrgloom @  20.5.2013,  11:40 Найти цитируемый пост)
но так же можно было бы и создать "пустой" класс

Ага, называется NULL.
Дело в том, что это логическая бомба. Если метод имеет тип возвращаемого значения, то программа ожидает это значение в 100% вызовов этого метода. Вызывать абстрактный метод априори не имеет смысла.

Если вам нужно создавать экземпляр класса, зачем его вообще делать абстрактным?
То, что вам нужно, можно и нужно реализовывать своими руками.
Если вам нужны пустые методы для переопределения в наследниках, то для этого существуют виртуальные методы:
Код

class Base
{
public:
    virtual const char* GetName() { throw new NotImplementedException(); }
}

переопределенные в дочернем классе, они заменят родительский метод даже, если указатель будет иметь тип родительского. В то же время можно создать экземпляр родительского класса. А при потребности можно выбросить исключение при вызове не переопределенного метода.

Абстрактный класс предназначен именно для случая, когда его экземпляр не должен создаваться по замыслу разработчика. Кроме того, в C++ абстрактный класс так же может являться и интерфейсом. Это значит, что разработчик требует, чтобы в задуманных местах объекты в любом случае имели предусмотренные поля и методы. При этом класс, описывающих набор этих методов, является лишь шаблоном (такой себе инструкцией) и заведомо не нуждается в создании своих экземпляров.

Это сообщение отредактировал(а) Arantir - 20.5.2013, 13:19


--------------------
interface Жопа {
    // ATTENTION: has to be implemented by every class of the project for proper project work
}
PM   Вверх
volatile
Дата 20.5.2013, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 37
Всего: 85



Цитата(mrgloom @  20.5.2013,  12:40 Найти цитируемый пост)
но вопрос то не в этом, а в том почему нельзя определить класс с абстрактным методом.
AbstractClass cl;
cl.domethod(); // путь тут так же и упадёт

Нельзя и всё! Воспринимайте как данность. 
Вообще, сделано для удобства программиста. Например, если в наследнике вы забудете определить какой-то абстрактный метод, то компилятор вам об этом ненавязчиво напомнит.  smile 

PM MAIL   Вверх
mrgloom
Дата 20.5.2013, 16:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



Так получается я всегда предполагается использовать только производный класс?
т.е. не
Код

Ptr<AbstractClass> cl;
cl= new ClassWithMethod(); 
cl->domethod(); 

а 
Код

ClassWithMethod cl; 
cl.domethod(); 


Цитата

You cannot use an abstract class as a parameter type, a function return type, or the type of an explicit conversion, nor can you declare an object of an abstract class. You can, however, declare pointers and references to an abstract class.

http://publib.boulder.ibm.com/infocenter/l...f%2Fcplr142.htm
так зачем мне может понадобиться ссылка на базовый класс?или в 1 месте я могу унаследовать 1 метод, в другом другой типа
Код

Ptr<AbstractClass> cl;
if()
cl= new ClassWithMethod1(); 
else
cl= new ClassWithMethod2(); 
cl->domethod(); 


еще вопрос с примером

Код

class CV_EXPORTS FeaturesMatcher
{
public:
    virtual ~FeaturesMatcher() {}

    void operator ()(const ImageFeatures &features1, const ImageFeatures &features2,
                     MatchesInfo& matches_info) { match(features1, features2, matches_info); }

    void operator ()(const std::vector<ImageFeatures> &features, std::vector<MatchesInfo> &pairwise_matches,
                     const cv::Mat &mask = cv::Mat());

    bool isThreadSafe() const { return is_thread_safe_; }

    virtual void collectGarbage() {}

protected:
    FeaturesMatcher(bool is_thread_safe = false) : is_thread_safe_(is_thread_safe) {}

    virtual void match(const ImageFeatures &features1, const ImageFeatures &features2,
                       MatchesInfo& matches_info) = 0;

    bool is_thread_safe_;
};


class CV_EXPORTS BestOf2NearestMatcher : public FeaturesMatcher
{
public:
    BestOf2NearestMatcher(bool try_use_gpu = false, float match_conf = 0.3f, int num_matches_thresh1 = 6,
                          int num_matches_thresh2 = 6);

    void collectGarbage();

protected:
    void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo &matches_info);

    int num_matches_thresh1_;
    int num_matches_thresh2_;
    Ptr<FeaturesMatcher> impl_;
};

void BestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2,
                                  MatchesInfo &matches_info)
{
    (*impl_)(features1, features2, matches_info);

//...


зачем нужна ссылка на базовый клас в производном классе?
Код

Ptr<FeaturesMatcher> impl_;


в BestOf2NearestMatcher::match
первой строчкой вызывается оператор ()
Код

(*impl_)(features1, features2, matches_info);


в переопределенном операторе
Код

void operator ()(const ImageFeatures &features1, const ImageFeatures &features2,
                     MatchesInfo& matches_info) { match(features1, features2, matches_info); }


и match используется уже от BestOf2NearestMatcher? причем мы нигде не указали, что impl_
должен использовать BestOf2NearestMatcher::match.
+ получается что BestOf2NearestMatcher::match внутри BestOf2NearestMatcher::match и рекурсия?(вообщем этот момент непонятен)

и что делает ?
Код

void operator ()(const std::vector<ImageFeatures> &features, std::vector<MatchesInfo> &pairwise_matches,
                     const cv::Mat &mask = cv::Mat());

PM MAIL   Вверх
Arantir
Дата 20.5.2013, 18:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Рыбак без удочки
**


Профиль
Группа: Участник
Сообщений: 960
Регистрация: 18.11.2012

Репутация: 1
Всего: 55



mrgloom, Ваша проблема в том, что Вы рассматриваете программу, как черный ящик. Попробуйте начать рассматривать ее как белый ящик.

Цитата(mrgloom @  20.5.2013,  15:31 Найти цитируемый пост)
Так получается я всегда предполагается использовать только производный класс?

Вы сами решаете, что предполагается использовать. И на основе этого создаете структуру программы. если предполагается любой класс с неким методом, то вы делаете указатель на абстрактный класс с этим методом. если предполагается конкретный Вами же написанный класс, то абстрактный класс для него не нужен.

Почитайте про фреймворки... Абстрактные классы весьма полезны, если предполагается, что ваш код — только каркас, и тот, кто его использует, часть функционала будет реализовать самостоятельно в виде собственных классов. Чтобы фреймворк мог эти классы использовать, то и используются указатели с типом абстрактного класса. В такой указатель может быть помещен объект класса, созданного пользователем фреймворка.


--------------------
interface Жопа {
    // ATTENTION: has to be implemented by every class of the project for proper project work
}
PM   Вверх
bsa
Дата 21.5.2013, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



mrgloom, очень сложные программы пишутся в виде модулей. Так удобнее писать и проще обслуживать. Возьмем для примера ядро Linux. Оно хоть и на С написано, но ООП там используется в полный рост.
Есть в нем некая подсистема. Устройств этого типа может быть куча, поэтому сразу же делается интерфейс для драйвера. Допустим, у драйвера должно быть 3 метода (ioctl, read, write). Вот разработчик подсистемы и делает класс с 3-мя чисто виртуальными функциями. Вся подсистема работает и взаимодействует с устройством через этот интерфейс.
Затем другой разработчик решил написать драйвер для устройства Х. Он пишет наследника класса-интерфейса и переопределяет эти методы. Теперь, подсовывая объект драйвера, подсистема начинает работать полноценно.
PM   Вверх
xvr
Дата 21.5.2013, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mrgloom @  20.5.2013,  16:31 Найти цитируемый пост)
зачем нужна ссылка на базовый клас в производном классе?

Это не ссылка на базовый класс - это ссылка на реализацию самого BestOf2NearestMatcher, причем она [реализация] находится не в родителе класса, а задается где то отдельно, снаружи. Это классическая реализация паттерна PIMPL

Цитата(mrgloom @  20.5.2013,  16:31 Найти цитируемый пост)
+ получается что BestOf2NearestMatcher::match внутри BestOf2NearestMatcher::match и рекурсия?

Нет. Эти match вызываются от разных объектов

PM MAIL   Вверх
mrgloom
Дата 21.5.2013, 12:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 829
Регистрация: 8.6.2011

Репутация: нет
Всего: нет



всё таки я не понял.
Код

void operator ()(const ImageFeatures &features1, const ImageFeatures &features2,
                     MatchesInfo& matches_info) { match(features1, features2, matches_info); }

откуда берется match?
я так понимаю, что если 
Код

virtual void match(const ImageFeatures &features1, const ImageFeatures &features2,
                       MatchesInfo& matches_info) = 0;

то match должна быть определена в классе наследнике, собственно говоря BestOf2NearestMatcher::match

но в ней первая же строчка непонятно для чего служит.
Код

 (*impl_)(features1, features2, matches_info);


impl_ как я понял нужно для того чтобы можно был овызывать функции из класса FeaturesMatcher, хотя зачем это нужно если мы и так от него унаследовались.

Это сообщение отредактировал(а) mrgloom - 21.5.2013, 12:24
PM MAIL   Вверх
xvr
Дата 21.5.2013, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(mrgloom @  21.5.2013,  12:13 Найти цитируемый пост)
откуда берется match?


Цитата(mrgloom @  21.5.2013,  12:13 Найти цитируемый пост)
то match должна быть определена в классе наследнике, собственно говоря BestOf2NearestMatcher::match

Именно так

Цитата(mrgloom @  21.5.2013,  12:13 Найти цитируемый пост)
но в ней первая же строчка непонятно для чего служит.

А вот это и есть вызов реализации. impl_ здесь смотрит не на родителя, а на другой экземпляр наследника FeaturesMatcher

Цитата(mrgloom @  21.5.2013,  12:13 Найти цитируемый пост)
impl_ как я понял нужно для того чтобы можно был овызывать функции из класса FeaturesMatcher, хотя зачем это нужно если мы и так от него унаследовались.

Мы не себя вызываем, а другого наследника. Класс FeaturesMatcher (и его наследники, в частности BestOf2NearestMatcher) описывают единственный тип, а вот экземпляров этих типов (т.е. непостредственно объектов) может быть созданно много. И при вызове метода происходит вызов именно от экземпляра объекта, а не от самого класса/типа.

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0721 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.