Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Unhandled exception


Автор: User008 6.5.2012, 16:10
Код

#include <memory>
#include <stdio.h>

class X
{
public:
    virtual void f() { printf("X::f"); }
};

class XD : public X
{
public:
    virtual void f() { printf("XD::f"); }
    virtual void ff() { printf("XD::ff"); }
};

class Y
{
public:
    Y() { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    virtual X *makeX() const { return new X; }
    std::auto_ptr<X> x;
};

class YD : public Y
{
public:
    virtual void f() { printf("YD::f"); }
    virtual void ff() { printf("YD::ff"); ((XD *)x.get())->ff(); }
protected:
    virtual X *makeX() const { return new XD; }
};

int main()
{
    try {
        YD yd;
        yd.ff();
    }
    catch(...) {
        printf("Exception");
    }
}

((XD *)x.get())->ff(); при выполнении этого возникает некий exception, который даже в catch не попадает. Что происходит?

Автор: User008 6.5.2012, 16:30
Если убрать virtual из XD::ff, то исключение не бросается. Не понимаю, что происходит.

Автор: borisbn 6.5.2012, 17:39
а с чего ради 
Цитата
((XD *)x

икс ( вернее x.get() )должен приводиться к XD *?

Автор: User008 6.5.2012, 17:53
Цитата(borisbn @  6.5.2012,  17:39 Найти цитируемый пост)
а с чего ради 
икс ( вернее x.get() )должен приводиться к XD *? 

Чтобы работать с ним как с указателем на объект класса XD - в данном примере, чтобы вызвать метод ff.

Автор: Randajad 6.5.2012, 19:55
Видимо в конструкторе недопустимо использовать виртуальные функции. smile

Автор: Sahab 7.5.2012, 00:32
Откройте для себя http://ru.wikipedia.org/wiki/Dynamic_cast...
http://liveworkspace.org/code/4eae1505583c04488e631626a517ba6e

Добавлено через 4 минуты и 49 секунд
Да... и segfault != exception

Автор: baldina 7.5.2012, 00:44
Цитата(User008 @  6.5.2012,  16:10 Найти цитируемый пост)
некий exception, который даже в catch не попадает

обращение по неверному адресу не родит исключение. ну если только компилятор+его настройки это не делают, но это нестандартно.
Цитата(Sahab @  7.5.2012,  00:32 Найти цитируемый пост)
Откройте для себя dynamic_cast

лучше откройте для себя http://ru.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B1%D1%80%D0%B8%D1%87%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)

Автор: User008 7.5.2012, 03:52
Цитата(baldina @  7.5.2012,  00:44 Найти цитируемый пост)
лучше откройте для себя фабрику 

Я думал то, что я написал и есть фабричный метод.

Автор: User008 7.5.2012, 10:34
Посмотрел примеры с фабричным методом. В тех, что я видел класс поля выбирается через параметр базового класса. А что если я не хочу делать базовый класс зависимым от классов, которые будут использованы в производных?

Автор: xvr 7.5.2012, 11:25
В вашей 'фабрике' вызов метода фабричного метода makeX делается в конструкторе, а там виртуальность не работает (т.е. ваша фабрика всегда будет порождать класс X), о чем вам Randajad тонко намекнул  smile 

Автор: User008 7.5.2012, 20:09
Цитата(xvr @ 7.5.2012,  11:25)
В вашей 'фабрике' вызов метода фабричного метода makeX делается в конструкторе, а там виртуальность не работает (т.е. ваша фабрика всегда будет порождать класс X), о чем вам Randajad тонко намекнул  smile

Да, спасибо, я это понял. А как сделать, чтобы при создании объекта поле становилось возвращаемым значением makeX?

Автор: baldina 7.5.2012, 22:08
Цитата(User008 @  7.5.2012,  10:34 Найти цитируемый пост)
если я не хочу делать базовый класс зависимым от классов, которые будут использованы в производных

то вы пишете функцию (или класс Фабрика), которая осведомлена о Ваших подклассах. Базовый, как правило, не знает, да и не должен

Автор: borisbn 8.5.2012, 09:23
Вот пару вариантов
Код

template< class T = X >
class Y
{
public:
    Y() { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    virtual X *makeX() const { return new T; }
    std::auto_ptr<X> x;
};

class YD : public Y< XD>
{
public:
    virtual void f() { printf("YD::f"); }
    virtual void ff() {
       printf("YD::ff");
       XD *xd = dynamic_cast<XD *>(x.get());
       if(xd)
          xd->ff();  
    }
};


Код

typedef std::function< X*() > makeX_t;

class Y
{
public:
    Y( makeX_t makeX ) { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    std::auto_ptr<X> x;
};

class YD : public Y
{
public:
    YD() : Y( [](){ return new XD; } ) {}
    virtual void f() { printf("YD::f"); }
    virtual void ff() {
       printf("YD::ff");
       XD *xd = dynamic_cast<XD *>(x.get());
       if(xd)
          xd->ff();  
    }
};

http://liveworkspace.org/code/659da452574be41e4d7a462d8403f101

Автор: User008 8.5.2012, 14:49
Я правильно понимаю, что если класс делается шаблонным, то его определения должны быть написаны в хедере, соответственно в тех файлах, в которых подключается этот хедер, его определения будут дублироваться?

Автор: baldina 8.5.2012, 14:59
да. шаблонный класс должен быть определен в каждой единице компиляции (кроме extern, но эта фича пока мало поддерживается)

Автор: User008 8.5.2012, 15:15
Цитата(baldina @ 8.5.2012,  14:59)
да. шаблонный класс должен быть определен в каждой единице компиляции (кроме extern, но эта фича пока мало поддерживается)

extern - может имеется в виду export?

Добавлено @ 15:20
Цитата(borisbn @ 8.5.2012,  09:23)
Вот пару вариантов
Код

template< class T = X >
class Y
{
public:
    Y() { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    virtual X *makeX() const { return new T; }
    std::auto_ptr<X> x;
};

class YD : public Y< XD>
{
public:
    virtual void f() { printf("YD::f"); }
    virtual void ff() {
       printf("YD::ff");
       XD *xd = dynamic_cast<XD *>(x.get());
       if(xd)
          xd->ff();  
    }
};


Код

typedef std::function< X*() > makeX_t;

class Y
{
public:
    Y( makeX_t makeX ) { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    std::auto_ptr<X> x;
};

class YD : public Y
{
public:
    YD() : Y( [](){ return new XD; } ) {}
    virtual void f() { printf("YD::f"); }
    virtual void ff() {
       printf("YD::ff");
       XD *xd = dynamic_cast<XD *>(x.get());
       if(xd)
          xd->ff();  
    }
};

http://liveworkspace.org/code/659da452574be41e4d7a462d8403f101

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

Автор: baldina 8.5.2012, 15:20
да, конечно))) заговорился

Автор: borisbn 8.5.2012, 16:04
Цитата(User008 @  8.5.2012,  15:15 Найти цитируемый пост)
Я правильно понимаю, что второй вариант относится к новому стандарту С++?

 smile 
можно и без 11-го
Код

typedef X*(*makeX_t)();

class Y
{
public:
    Y( makeX_t makeX ) { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    std::auto_ptr<X> x;
};

class YD : public Y
{
public:
    YD() : Y( makeXD ) {}
    virtual void f() { printf("YD::f"); }
    virtual void ff() {
       printf("YD::ff");
       XD *xd = dynamic_cast<XD *>(x.get());
       if(xd)
          xd->ff();  
    }
    static X* makeXD() { return new XD; }
};

http://liveworkspace.org/code/758c42a323364d99c46e0d98f17bae12

Цитата(User008 @  8.5.2012,  15:15 Найти цитируемый пост)
А как можно реализовать первый вариант без использования шаблона?

там весь смысл в шаблоне... тога уж его (вариант) нужно не реализовать без шаблона, а реализовать по-другому

Автор: User008 8.5.2012, 18:12
[QUOTE=borisbn,8.5.2012,  16:04]
Цитата(User008 @  8.5.2012,  15:15 Найти цитируемый пост)

Код

typedef X*(*makeX_t)();

class Y
{
public:
    Y( makeX_t makeX ) { x = std::auto_ptr<X>(makeX()); }
    virtual void f() { printf("Y::f"); }
protected:
    std::auto_ptr<X> x;
};

class YD : public Y
{
public:
    YD() : Y( makeXD ) {}
    virtual void f() { printf("YD::f"); }
    virtual void ff() {
       printf("YD::ff");
       XD *xd = dynamic_cast<XD *>(x.get());
       if(xd)
          xd->ff();  
    }
    static X* makeXD() { return new XD; }
};

Вот это похоже то, что мне нужно.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)