2014-01-08 1 views
3

EDIT Ответил: Хотя мой первоначальный вопрос не объяснил мои потребности точно так, как ответил им Конрад Рудольф, он (случайно или по дизайну) написал для меня то, что я пытался написать! Сам класс не расширяется, но его функциональность расширяется за счет того, что класс знает о новых функциях, которые позволяют ему (классу) обрабатывать более широкий спектр проблем. Мое благодарное спасибо за отличный ответ, который, в свою очередь, также отличный учебник, даже если для этого требуется какой-то свет ахм? чтение книг мной ;-).Расширение класса

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

Для моего проекта я определяю class error_handler {}, который обрабатывает сообщения об исключениях и номера ошибок из программ разных точек. Он зарегистрирует ошибку в файле и/или распечатает сообщение на экране с помощью различных функций-членов.

Моя цель - создать его так, чтобы он имел свои собственные .h и .cpp-файлы, и, если мне потом нужно его расширить, просто добавьте новую функцию-член, чтобы обрабатывать некоторые более неясные типы ошибок. затем

Мой вопрос заключается в следующем:

Поскольку в error.h У меня есть код:

class error_handler 
{ 
    // ctor dtor copy logger screen functions defined 
} 

И в error_handler.cpp я заканчиваю эти определения,

Как я могу просто просто добавить новую функцию к классу? Я не хочу подклассифицировать его, просто продлить его.

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

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

+2

Обычная (и по существу единственный) способ расширить класс является «суб-класс» он (т.е. извлечь из него). «Я не хочу подклассифицировать его, просто продлить». звучит немного как «Я хочу плавать, не промокая». –

+0

@JerryCoffin Ну, есть некоторые грязные макросы, используемые в некоторых (довольно зрелых и профессиональных) проектах. Однако, возможно, если вы действительно не знаете, что делаете, вы должны использовать механизм деривации/наследования, особенно на начальном уровне. – luk32

+1

@NeonGlow Я могу думать о ** по крайней мере ** тремя способами без наследования. И на самом деле мой любимый выбор здесь, вероятно, не будет наследованием. –

ответ

2

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

Чтобы это было просто, предположим, что каждая функция (назовем ее handle) просто получает переданный объект ошибки, который он анализирует и обрабатывает, или не обрабатывает. Он возвращает bool, чтобы указать это.

Тогда вы могли бы иметь следующий (упрощенный) error_handler класса:

class error_handler { 
public: 
    using handler_t = bool (*)(error const&); 
    std::vector<handler_t> handlers; 

    // … 

    void add_handler(handler_t handler) { 
     handlers.push_back(handler); 
    } 

    void handle_error(error const& error) { 
     for (auto const& handler : handlers) 
      if (handler(error)) 
       break; 
    } 
}; 

Это предполагает, что ваши ошибки представляется экземпляром класса error (и что вы используете C++ 11 - синтаксис немного меняется).

Теперь, для определения этого класса исправлено. Вы можете добавить другие обработчики, определенные в других файлах, просто путем вызова add_handler`. Вот два примера:

// Simple logging “handler”. Needs to be added first! 

extern error_handler global_error_handler; 

bool log_handler(error const& error) { 
    std::cerr << error.message() << '\n'; 
    return false; // We only log, we don’t handle. 
} 

global_error_handler.add_handler(log_handler); 
// Handler for missing dog food 

extern error_handler global_error_handler; 

errno_t const MISSING_DOG_FOOD = 42; 

bool dog_food_missing(error const& error) { 
    if (error.code() != MISSING_DOG_FOOD) 
     return false; 

    global_dog_food_container.add(some_food()); 
    return true; 
} 

global_error_handler.add_handler(dog_food_missing); 
+0

WOW !! Более того, чем я ожидал! Вы добавили некоторые функции, с которыми я не знаком, поэтому я читаю больше. (В частности, 'using handler_t = bool (*) (error const &);' где я не видел 'использование' в этом контексте) Спасибо за чудесно подробный пример! – Jase

+0

Будучи новым для C++ 11 У меня есть пара вопросов об этом коде, который я до сих пор не могу разобраться (хотя он отлично работает). Я не хочу загромождать SO с этим, если бы вы были добры, чтобы связаться со мной по электронной почте на моей странице профиля? Я был бы очень признателен. – Jase

+0

Является ли это «цепочкой команд»?И мне любопытно, какие два других способа вы упомянули? –

2

В C++ вы не можете изменить класс без изменения блока class и добавление определения функции (т. е. в error.h)

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

+0

grrr ... это то, чего я боялся. Объясняет, почему книга не ссылалась на эту концепцию. – Jase

+1

@Jase: Это тоже имеет смысл. Вы могли бы вызвать всевозможные хаосы, если бы вы могли произвольно переписывать типы из разных единиц перевода! –

+0

@LightnessRacesinOrbit - LOL - Да, это было бы! Я согласен с (мое свободное понимание), почему это невозможно. Это создало бы всевозможные проблемы. Но со знанием есть сила, и я стремлюсь понять язык, а не втягивать его в новые и неясные формы и направления. Спасибо, что переосмыслил это для меня. Это было упомянуто в книгах, но до сих пор я не смог установить связь. – Jase

1

Единственный способ расширить класс без изменения его первоначального определения - это создать новый класс, полученный из него. Возможно, вы должны быть более конкретными с тем, что вы пытаетесь сделать. Ваши изменения изменит существующий код, который использует error_handler? Например, если вы просто хотите добавить функцию, которая будет регистрировать ошибку по-другому, и только намерена использовать эту функцию в вашем новом коде, вы можете использовать для нормальной, не-членной функции, которая принимает ссылку error_handler , но более чистым способом было бы создать класс my_error_handler (производный) с новым методом. Указатель/ссылка на экземпляр my_error_handler может быть свободно преобразован в указатель/ссылку на error_handler, если вы хотите передать его существующему коду.

+0

Не знаете, как перейти к преобразованию указателя/ссылки. Я (возможно, глупо), немного подпрыгивая в книгах, пытаясь переписать очень старый код как способ изучения новых концепций. (Исходный код был C = 64 basic) – Jase