Убедитесь, что конструктор производного класса должен вызывать определенный метод базового класса

В классе C++(03) у меня есть переменная-член, которой должно присваиваться значение во время создания объекта. Однако только производный класс может вычислить требуемое значение. Как обсуждалось в этом сообщении C++ требует, чтобы вы инициализировали члены базового класса из его производного класса?, я понимаю, что производный класс не может инициализировать член базового класса, но для меня достаточно присваивания.

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

class Base {
public:
    Base() {}
    setFoo(unsigned inFoo) { foo = inFoo; }
private:
    unsigned foo;
};

class Derived : public Base {
    Derived() : Base() { 
        unsigned desired = ... // do calculations to get the desired value
        setFoo(desired);  // --> how to ensure that derived class calls this?
    }
};

Затем foo используется несколькими другими методами базового класса. Даже если я установлю «флаг» в setFoo(), нет метода «пост-конструктор», где я мог бы это проверить. В базовом классе есть несколько других методов, в которых используется foo. Я мог бы проверить это там, но это слишком утомительно, подвержено ошибкам и неэффективно.

Мои извинения, если это было задано раньше. Я пытался найти его здесь, прежде чем спрашивать, выполнив поиск «Убедитесь, что конструктор производного класса должен вызывать определенный метод базового класса» и «Принудительно производный класс для назначения члена базового класса». Я наткнулся на несколько полезных сообщений Как я могу инициализировать константную переменную базового класса в конструкторе производного класса в C++? и Заставить производный класс использовать конструктор базового класса , но они, к сожалению, не решают мой вопрос.

Не могли бы вы предложить мне подходящий подход к разрешению этой ситуации? Желательна проверка во время компиляции, но если это невозможно, также может помочь проверка во время выполнения. Хотя я не могу использовать C++11 для решения своей проблемы, я был бы рад узнать о любых решениях C++11. Спасибо за внимание.

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

Edit2 Я согласен с ответами о том, что значение должно быть передано в параметре конструктора, и если бы мне пришлось писать Base с нуля, я бы не просил такой подход. Проблема в том, что из-за устаревших причин Base уже имеет несколько параметров конструктора (9), и я надеялся избежать добавления дополнительных (3), «выгружая» их в тело конструктора. Однако в долгосрочной перспективе код должен быть рефакторинг.

Edit3 Извините за столько правок. Я могу изменить класс Base по своему усмотрению, но класс Derived находится в клиентском коде, которым я не могу управлять.


person Masked Man    schedule 09.12.2012    source источник


Ответы (3)


Если конструктор производного класса должен вызывать setFoo(), то я думаю, что это проблема дизайна. Лучше спроектировать базовый класс так, чтобы его конструктор принимал желаемое значение в качестве аргумента, а производный класс передал вычисленное значение как:

class Base {
public:
    Base(unsigned int foo) : m_foo (foo) {}  //define this constructor
private:
    unsigned int m_foo; //member data
};

class Derived : public Base {
    Derived() : Base(computeValue()) 
    { 
    }
private:
    static unsigned int computeValue() //it may take argument(s)
    {
        unsigned int desired = ... //do calculations to get the desired value
        return desired;
    }
};
person Nawaz    schedule 09.12.2012
comment
+1, но бесполезно использовать одно и то же имя для переменной-члена и формального аргумента. пожалуйста, исправьте это. - person Cheers and hth. - Alf; 09.12.2012
comment
@Cheersandhth.-Альф: Готово. :-) - person Nawaz; 09.12.2012
comment
Спасибо за ответ. Я согласен, что это не очень хороший дизайн, но проблема в том, что из-за устаревших причин конструктор базового класса имеет несколько параметров, и мне нужно его расширить. Я надеялся найти способ избежать добавления дополнительных параметров. В долгосрочной перспективе код придется рефакторить. Я полагаю, мне следовало прояснить это в самом вопросе, приношу свои извинения за то, что упустил это. - person Masked Man; 09.12.2012
comment
-1 этот подход использует статическую функцию, что плохо, потому что производный класс может захотеть установить свое состояние в соответствии со значением, которое он передает базовому классу. - person Roee Gavirel; 09.12.2012
comment
@RoeeGavirel: конструктор все равно может это сделать. Кроме того, это всего лишь основная идея. Если он должен быть нестатическим членом, то OP может сделать это в любое время, но это тоже не лучшая идея, потому что функция-член может в конечном итоге получить доступ к другим неинициализированным данным-членам, поскольку объект не полностью построен. Если это так, то это неопределенное поведение. - person Nawaz; 09.12.2012
comment
@ap: я надеялся найти способ избежать добавления дополнительных параметров - это другой вопрос SO. выкладывай отдельно. - person Cheers and hth. - Alf; 09.12.2012
comment
@Cheersandhth.-Alf Спасибо за совет. Я так и сделаю. - person Masked Man; 09.12.2012

Если для построения объекта требуется значение, оно должно быть параметром конструктора.

class Base {
public:
    Base(unsigned inFoo) { setFoo(inFoo); }
    setFoo(unsigned inFoo) { foo = inFoo; }
private:
    unsigned foo;
};

class Derived : public Base {
    Derived() : Base(compute_desired()) { }

};

Здесь compute_desired может быть членом Derived или просто любой функцией, выполняющей вычисления.

person Bo Persson    schedule 09.12.2012

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

person Chubsdad    schedule 09.12.2012
comment
Базовый класс может быть изменен, извините, что не указал это в вопросе. - person Masked Man; 09.12.2012