2016-01-24 1 views
1

У меня есть некоторые исключения, полученные от std::exception или std::runtime_error. Единственный метод - конструктор explicit MyExceptionX(const char *text = "") : std::exception(text) {}. Есть ли способы сделать этот код проще без использования макроса?Как автоматизировать объявления классов?

class MyException1: public std::exception 
{ 
public: 
    explicit MyException1(const char *text = "") : std::exception(text) {} 
}; 

class MyException2: public std::exception 
{ 
public: 
    explicit MyException2(const char *text = "") : std::exception(text) {} 
}; 

class MyException3: public std::exception 
{ 
public: 
    explicit MyException3(const char *text = "") : std::exception(text) {} 
}; 

//... 
+2

Ваш код должен быть скомпилирован? – juanchopanza

+0

Я думаю, что это действительный случай использования макроса. –

+0

Что я имел в виду, пожалуйста, напишите какой-то код, который, по крайней мере, компилируется. – juanchopanza

ответ

7

Нет необходимости использовать class, когда все открыто. Вместо этого вы можете использовать struct. Кроме того, вы можете наследовать конструкторами:

struct MyException1: std::exception 
{ 
    using std::exception::exception; 
}; 

struct MyException2: std::exception 
{ 
    using std::exception::exception; 
}; 

struct MyException3: std::exception 
{ 
    using std::exception::exception; 
}; 

Кроме того, если вы на самом деле просто нужны разные типы, то вы можете сделать это:

template <int> 
struct MyException : std::exception 
{ 
    using std::exception::exception; 
}; 


using MyException1 = MyException<1>; 
using MyException2 = MyException<2>; 
using MyException3 = MyException<3>; 

Вы можете использовать enum вместо int если вы хотите более описательный имена.

+0

Мне нравится ваше предложение, но я обычно использую его с 'enum' так:' enum class my_problems {no_money, no_love, no_sleep}; template struct my_exception: std :: exception {}; 'Тогда вы можете сказать такие вещи, как' my_exception ', которые я нахожу очень выразительными. Возможно, вам больше не понадобится псевдоним 'using'. – 5gon12eder

+0

@ 5gon12eder: Согласен. Я начал делать это таким образом, но в этом примере это выглядело глупо: 'enum class ExceptionId {one, two, three}'. –

+0

Я понимаю, что вы имеете в виду. Это проблема с надуманными примерами. – 5gon12eder

0

Вы можете быть using конструктором суперкласса. Следующий упрощенный пример кода, что вы ищете:

#include <iostream> 

class A { 
public: 
    A(char* cText) { 
    std::cout << cText << std::endl; 
    } 

    ~A() { 
    } 
}; 

class B : public A { 
public: 
    using A::A; 

    ~B() { 
    } 
}; 

int main(int argc, char** argv) { 
    B("Test"); 

    return 0; 
} 

Кроме того, функция using для наследования конструкторов доступна только при компиляции с -std=c++11 или -std=gnu++11.

+0

вам нужно пометить '~ A()' a 'virtual' destructor –

+0

Лучшим решением было бы не использовать' new' и 'delete' вообще. – juanchopanza

+0

@BryanЧен нет, вы этого не делаете. Он работает как шарм, не делая '~ A()' virtual. Создание виртуального на самом деле * chages *, что эффект полиморфизма w.r.t. что выполняется при деконструировании класса. Кроме того, полиморфизм деструктора не подлежит сомнению. –

0

Следующих отлично компилируется в моем VisualStudio 2012:

template <const char *&text> 
class MyException: public std::exception 
{ 
public: 
    virtual const char* what() const { return(text); } 
}; 

const char *Ex1 = "Message1"; 
const char *Ex2 = "Message2"; 
const char *Ex3 = "Message3"; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    throw MyException<Ex1>(); 
    throw MyException<Ex2>(); 
    throw MyException<Ex3>(); 
    return 0; 
} 

К сожалению, C++ не позволяет использовать строковые литералы в самом вбрасывания заявлении. Подробности можно найти здесь: String literals not allowed as non type template parameters.

Смежные вопросы