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


Автор: Kipter 24.2.2010, 23:48
Суть такова....

У каждого класса есть свой набор всевозможных ошибок которые могут происходить в его функциях.
например...

Код

class TCPClient {
public:
    enum SockErrors { ERR_INIT, ERR_CONNECTING, ERR_READING, ERR_WRITING, ERR_DISCONNECTED };

... трататата тело ...
}; 

class HTTPClient {
       enum HttpErrors { NOTFOUND, BADREQUEST, FORBIDDEN, SERVERERROR };

.... трататата тело...
};


Класс-исключение для всех классов вообщем то по коду одинаков и тупо копипастить его для каждого класса было бы наверное глупо.
Однако использовать его для всех классов не приемлемо ибо будут совпадать коды ошибок а в каком классе именно произошло исключение будет неясно.

Код

class XException : public std::exception {
public:
    XException(const char* message, const uInt inErrorCode = NULL);
    virtual ~XException() throw() {};

    virtual const char* what() const throw();
    virtual const uInt errorCode() const throw();

protected:
    uInt    mErrorCode;
    string    mMessage;
};


используется как

Код

throw XException("Ну вот упало потому что ананасы",  ERR_CONNECTING);


тогда я сделал так

Код

#define IMPL_EXCEPTION(newname, parent)                        \
class newname : public parent {                                \
public:                                                    \
    newname(const char* message, const uInt inErrorCode = NULL)    \
    : parent(message, inErrorCode) {};                        \
};                                                                                                   


Код

class TCPClient {
public:
      IMPL_EXCEPTION(except, XException);
      enum SockErrors { ERR_INIT, ERR_CONNECTING, ERR_READING, ERR_WRITING, ERR_DISCONNECTED };

... трататата тело ...
}; 

class HTTPClient {
       IMPL_EXCEPTION(except, XException);
       enum HttpErrors { NOTFOUND, BADREQUEST, FORBIDDEN, SERVERERROR };

.... трататата тело...
};

void main()
{
  HTTPClient client;
  try {
     client.downloadFile("http://toptoptop.top/fox.jpg");
  }
  catch(TCPClient::except &excp)
  {
    ... Исправляем ситуацию по кодам ошибок TCPClient ...
  }
  catch(HTTPClient::except &excp)
  {
    ... Исправляем ситуацию по кодам ошибок HTTPClient ...
  }
}


Собственно смущает вопрос правильности подхода... поидее для каждого класса генерируется код еще под  один конструктор нового типа исключения, да и пришлось использовать макро-определение..... Да и думаю не ожидают ли подводные камни....

есть идеи?

P.S: 
Не хватает оператора что то вроде typedef но который бы делал не ассоциацию типа а вводил новый тип но только для правил компилятора =)

Автор: mes 25.2.2010, 00:16
почитайте про шаблоны (template<>)

Автор: Kipter 25.2.2010, 00:50
Цитата(mes @  25.2.2010,  00:16 Найти цитируемый пост)
почитайте про шаблоны (template<>) 


Хе-хе, про шаблоны знаю.... но не получу ли я ими еще более излишнюю кодогенерацию? 
тогда для каждого класса будет сгенерирован не только излишний конструктор но и функции члены!

получим еще больше лишнего коду ради "удобства"

Да и ктомуже синтаксис красивше не станет! я бы сказал появится даже больше нагромождений.

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

Автор: Kipter 25.2.2010, 01:20
Цитата(mes @  25.2.2010,  00:16 Найти цитируемый пост)
почитайте про шаблоны (template<>) 


Хе-хе, про шаблоны знаю.... но не получу ли я ими еще более излишнюю кодогенерацию? 
тогда для каждого класса будет сгенерирован не только излишний конструктор но и функции члены!

получим еще больше лишнего коду ради "удобства"

Да и ктомуже синтаксис красивше не станет! я бы сказал появится даже больше нагромождений.

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

Добавлено через 12 минут и 15 секунд
Вот вариант с использование Специализированных шаблонов о которых говорил mes
ссори за грязное исполнение в одном фаиле и реализацией по месту объявления, просто так быстрее =)

Код

template <typename T>
class XException {};

class XPrivateException : public std::exception {
public:
    XPrivateException(const char* message, const int inErrorCode = NULL) 
        : mErrorCode(inErrorCode), mMessage(message) {};
    virtual ~XPrivateException() throw() {};

    virtual const char* what() const throw() 
        { return mMessage.c_str(); }
    
    virtual const int errorCode() const throw() 
        { return mErrorCode; }

protected:
    int          mErrorCode;
    string    mMessage;
};


class TCPClient;

template<>
class XException<TCPClient> : public XPrivateException {
public:
    XException(const char* message, const int inErrorCode = NULL) 
        : XPrivateException(message, inErrorCode) {};
};

class TCPClient {
public:
    enum SockErrors { ERR_INIT, ERR_CONNECTING, ERR_READING, ERR_WRITING, ERR_DISCONNECTED };
    
    void Start() { throw XException<TCPClient>("TCP", 1); }
}; 


class HTTPClient;

template<>
class XException<HTTPClient> : public XPrivateException {
public:
    XException(const char* message, const int inErrorCode = NULL) : XPrivateException(message, inErrorCode) {};
};

class HTTPClient {
public:
    enum HttpErrors { NOTFOUND, BADREQUEST, FORBIDDEN, SERVERERROR };

    void Start1() { tcp.Start(); }
    void Start2() { throw XException<HTTPClient>("HTTP", 3); }

    TCPClient tcp;
};


void main()
{
    HTTPClient client;
    try {
        client.Start1();
    }
    catch(XException<TCPClient> &excp)
    {
        cout << "XException<TCPClient>" << endl;
        cout << excp.what() << endl;
    }
    catch(XException<HTTPClient> &excp)
    {
        cout << "XException<HTTPClient>" << endl;
        cout << excp.what() << endl;
    }
}


Собственно что дает? Убили макроопределение....
С шаблонами есть типо как проверка типов, случайно не сунешь левый тип =) (реализация увы неполная поэтому в данном примере сунешь)
Но с другой стороны сунув левый тип в макро - тоже ошибку получишь, глянешь в макрос и все поймешь + можно комменты к нему накидать.

В плане кодогенерации получаем тоже самое что и с макросом + код конструктора каждому классу.

Но теперь нам необходимо выкидывать исключения вот так: throw XException<HTTPClient>("HTTP", 3); 
заместо возможного throw XException("HTTP", 3); c макросом.

и писать перед каждым классом 

Код

template<>
class XException<HTTPClient> : public XPrivateException {
public:
    XException(const char* message, const int inErrorCode = NULL) : XPrivateException(message, inErrorCode) {};
};


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

Автор: mes 25.2.2010, 01:57
Цитата(Kipter @  25.2.2010,  00:20 Найти цитируемый пост)
Хе-хе, про шаблоны знаю.... но не получу ли я ими еще более излишнюю кодогенерацию? 
тогда для каждого класса будет сгенерирован не только излишний конструктор но и функции члены!

не больше чем макросом smile 
Цитата(Kipter @  25.2.2010,  00:20 Найти цитируемый пост)
Вот вариант с использование Специализированных шаблонов о которых говорил mes

нет, я говорил о несколько другом варианте, вот набросок :
Код

template <class Code> XException : public XBaseException
{
    XException (const char  *msg, Code code) ...
};

struct TestClass
{
   enum ECode { eTestCode = 100 };
   typedef XEception<ECode> Exception;
 
  void test_except () { throw Exception ("test msg", eTestCode ); }
      
};
...
   TestClass test;
    try {
        test.test_except ();
    }
    catch(TestClass::Exception &excp)
    {
        cout << "TestClass::Exception" << endl;
        cout << excp.what() << endl;
    }


ну а дальше уже делайте вариацию под Ваши цели smile



Автор: Kipter 25.2.2010, 02:05
mes,  smile 

Чорт, действительно, красива.... 

Надо высыпаться то то бредни в голову к вечеру лезут.

Спасибо++

Автор: bilbobagginz 25.2.2010, 23:06
mes, а зачем сразу шобло ны ? может лучше просто создать базовый классик. с частично виртуальными методами.
а в сыновьих классах эти виртуалки реализовать в соответствии с требованиями.
я не знаю что выгоднее - шаблоны или наследование ?

UPD: 
сначала я понял будто у каждого из классов будут особенные эксепшены, разных типов - разным количеством данных на выходе, разными what(), и т.п.
а сейчас взглянул на примеры, и получается, что никаких принципиально разных эксепшенов ему тут не надо. 
можно обойтись действительно с шаблонами... довольно читабельно, и ручками писАть меньше.


Автор: Lazin 25.2.2010, 23:19
Цитата(Kipter @  24.2.2010,  23:48 Найти цитируемый пост)
тогда я сделал так

а вот зачем интересно
обычно для каждого класса не нужно городить свой класс исключения, все равно в большинстве случаев будешь ловить через std::exception  smile 

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