Заглушка ненужых методов базового класса

Доброго времени суток :)
Такое дело. Есть класс Vector, объекты которого являются обычными векторами на Декартовой плоскости. Есть класс GravityForce, объекты которого представляют силу гравитационного взаимодействия между двумя телами на той же плостоски, а так как любая сила есть векторная величина, то класс GravityForce является дочерним по отношению к Vector. И всё бы ничего, но в классе Vector есть set'теры для изменения базиса вектора, которые очень нежелательны в GravityForce, ибо все расчёты базиса происходят автоматически при вызове других методов. В связи с чем назревает вопрос: как «убрать» их из класса GravityForce? Единственное, что идёт в голову — написать заглушки, которые при своём вызове ничего не изменяют, но мне такое решение кажется неправильным :(

А должен ли быть класс GravityForce дочерним по отношению к классу Vector?

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

М-да?.. Например, есть класс Point, реализующий абстракцию геометрической точки. Класс Circle, реализующий абстракцию геометрического круга, должен быть дочерним по отношению к Point? А класс Rectangle (прямоугольник)?

Нет, потому что круг не является точкой и прямоугольник тоже.
А вот класс Square, описывающий квадрат вполне себе может быть унаследован от Rectange, потому что все свойства прямоугольника применимы и к квадрату.

дочерним по отношению к Point?

Нет, поскольку круг не есть точка. А в моём случае сила есть вектор.

porshe, мне сложно что-то аргументированно доказывать, поскольку я не знаю какую задачу (глобальную) ты решаешь и не знаю деталей реализации ни GravityForce, ни Vector. Я только намекнул на то, что возможно тебе не надо наследовать GravityForce от Vector, а иметь Vector в качестве закрытого члена GravityForce.

Наследование — штука... опасная. Есть хорошее правило: использовать наследование только в том случае, если оно действительно необходимо. (А при множественном наследовании — опасность возрастает в степени пропорциональной количеству классов-предков. Это так, к слову.)

По поводу геометрических примитивов. Я видел в каком-то пособии по ООП следующее рассуждение. Круг — это точка (центр круга), у которой есть радиус. Прямоугольник — это точка, у которой есть длина и ширина (т.е. длины сторон). Т.е. при такой идеологии базовый класс Точка в дочерних классах выступает в качестве точки привязки фигуры. Такое рассуждение, в принципе, имеет право на существование. Однако при развитии такой системы абстракций очень быстро возникают существенные сложности. Поэтому её реальное применение проблематично.

Следовательно, на начальном этапе проектирования программы надо хорошо подумать и аргументированно решить что лучше использовать наследование, агрегирование или композицию. Кстати, этот момент является одним из объектов критики ООП: на этапе начального проектирования классов необходимо предвидеть потребности, которые возникнут в будущем.

Для любознательных пара ссылок на Википедию:
пять типов ассоциации
Агрегирование (программирование)

Я нуден, да?

Единственное, что идёт в голову — написать заглушки, которые при своём вызове ничего не изменяют

Можно использовать приватное наследование. Но тогда для доступа к функциям приватного базового класса через интерфейс дочернего, в дочернем классе придётся написать публичные функции-обёртки. Доступ к тем функциям базового класса, для которых не будет обёрток, пользователям дочернего класса будет закрыт. Кстати, по умолчанию, классы наследуются как приватные. Что-то типа такого:

#include <iostream>

using namespace std;

class A {
public:
    void a1() { cout << "A::a1()" << endl; }
    void a2() { cout << "A::a2()" << endl; }
};

class B : A {  // !!! не 'public A' !!! но можно написать и явно: 'private A'
public:
    void a2() { A::a2(); cout << "B::a2()" << endl; }
};

int main()
{
    B b;

    //b.a1();      // ошибка. Функция a1 недоступна.
    b.a2();

    return 0;
}

Спасибо за содержательный ответ :)

я не знаю какую задачу (глобальную) ты решаешь

Если совсем глобально — симулятор гравитационного взаимодействия тел, если чуть более локально — пишу класс GravityObject — для представления объектов с массой. У каждого объекта есть массив сил и «скоростей», действующих на объект. Силы представляются с помощью GravityForce, скорость с помощью Vector.

Можно использовать приватное наследование

Да, что-то подобное я и хотел реализовать.

Я нуден, да?

Нет. Наоборот, интересно читать замечания опытного человека, ведь этого нет в книгах :)

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

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

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.