2015-10-04 2 views
2

Я в настоящее время сталкивается следующий сценарий:переменная член Force быть построено базового класса

class foo 
{ 
public: 
    foo (/* some parameters */); 
}; 

class bar 
{ 
public: 
    bar (foo & f); 
}; 

// both foo and bar are 3rd party 

class base 
{ 
public: 
    base (foo & f) : m_bar (f) {} 

private: 
    bar m_bar; 
}; 

class derived : public base 
{ 
public: 
    derived (foo & f) : base (f) {} 
}; 

class derived2 : public base 
{ 
public: 
    derived2() : base (/* well ... */) {} 

private: 
    foo m_foo; 
}; 

Как вы можете видеть, foo и bar были предназначены для использования, как это:

foo f (/* some parameters */); 
bar b (f); 

Тем не менее, я хочу, чтобы мои классы-оболочки были автономными, если необходимо, и derived2 должен быть. Но, derived2::m_foo не может быть просто передан base, а его неинициализирован.

Так что мой вопрос: есть ли способ заставить derived2::m_foo построить до base?

Единственное решение, которое я придумал себе это:

class derived2_foo 
{ 
protected: 
    foo m_foo; 
}; 

class derived2 : public base, public derived2_foo 
{ 
public: 
    derived2() : derived2_foo(), base (m_foo) {} 
}; 

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

+0

Хм .. вы не должны изменять вопрос, чтобы включить ответ. Будущие читатели вопроса + ответа будут смущены тем фактом, что я, кажется, ответил на то, что вы уже знали. –

+0

@ChristianHackl Извините, не знал этого. И не знаю, как вернуть изменения.Но ваш аргумент также относится к первой версии вашего ответа, которая просто устанавливает 'производный2_foo' в' private', что могло быть сделано в комментарии. Мой вопрос касается других идей, кроме моих. Во всяком случае, я дважды отредактирую свой вопрос – andyb

+0

Не большое дело. Просто имейте в виду, что главная цель SO заключается в создании огромной базы знаний Q/A. Возможно, ваш вопрос также лучше подходит для codereview.stackexchange.com; в конце концов, похоже, у вас уже есть рабочее решение, но не уверен, что он хороший. –

ответ

4

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

class derived2_foo 
{ 
protected: 
    foo m_foo; 
}; 

class derived2 : private derived2_foo, public base 
{ 
public: 
    derived2() : derived2_foo(), base (m_foo) {} 
}; 

Я также изменил порядок, в котором ваши базовые классы появляются в объявлении класса. Всегда убедитесь, что порядок в объявлении класса совпадает с порядком в списке инициализации (как и с переменными-членами). Как C++ FAQ говорит:

Обратите внимание, что порядок B1 и B2 затем [...] определяется порядок, что базовые классы появляются в объявлении класса, не в том порядке, инициализатор появляется в списке инициализации класса .

Или еще более официальный источник, стандарт C++ на §12.6.2/13,2:

[...] прямые базовые классы инициализируются в порядке декларации, как они появляются в base-specifier-list (независимо от порядка mem-initializers).

Еще одно усовершенствование было бы поставить derived2_foo класс в свой собственный "частный" пространство имен:

namespace detail 
{ 
    class derived2_foo 
    { 
    protected: 
     foo m_foo; 
    }; 
} 

class derived2 : private detail::derived2_foo, public base 
{ 
public: 
    derived2() : derived2_foo(), base (m_foo) {} 
}; 

библиотеки как Boost, сделать это, тоже. Хотя пространство имен detail технически не скрывает и не защищает, оно сигнализирует клиентам, что они не должны зависеть от его содержимого.

+0

(отредактируйте: этот комментарий не совсем прав, но я оставляю его как часть обсуждения). Также стоит отметить, что христианин изменил порядок наследования для 'производного2', чтобы убедиться, что' производный2_foo' построен сначала перед «базой». – Cornstalks

+0

@Cornstalks: На самом деле, это только проблема с кодировкой. Порядок, в котором перечислены базовые классы, не является существенным, если вы явно указываете порядок вызовов базового конструктора через список инициализации. –

+0

Прохладный, спасибо, что научил меня чему-то новому. Означает ли это, что если есть несколько конструкторов, все они должны всезывать суперконструкторы в одном порядке (так что разрушение всегда происходит в обратном порядке)? – Cornstalks

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