Во-первых, я знаю, что не могу этого сделать, и я думаю, что это не повторяющиеся вопросы ( это и это вопросы касаются той же проблемы, но они хотят толькообъяснение того, почему это не работает).
Итак, у меня есть похожая концепция классов и наследования, и я хотел бы, так или иначе, элегантно хотеть сделать то, что запрещено.Вот очень простой фрагмент кода, который отражает то, что я хочу сделать:
#include <iostream>
class A{
protected:
int var;
std::vector <double> heavyVar;
public:
A() {var=1;}
virtual ~A() {}
virtual void func() {
std::cout << "Default behavior" << this->var << std::endl;
}
// somewhere along the way, heavyVar is filled with a lot of stuff
};
class B: public A{
protected:
A* myA;
public:
B(A &a) : A() {
this->myA = &a;
this->var = this->myA->var;
// copy some simple data, e.g. flags
// but don't copy a heavy vector variable
}
virtual ~B() {}
virtual void func() {
this->myA->func();
std::cout << "This class is a decorator interface only" << std::endl;
}
};
class C: public B{
private:
int lotsOfCalc(const std::vector <double> &hv){
// do some calculations with the vector contents
}
public:
C(A &a) : B(a) {
// the actual decorator
}
virtual ~C() {}
virtual void func() {
B::func(); // base functionality
int heavyCalc = lotsOfCalc(this->myA->heavyVar); // illegal
// here, I actually access a heavy object (not int), and thus
// would not like to copy it
std::cout << "Expanded functionality " << heavyCalc << std::endl;
}
};
int main(void){
A a;
B b(a);
C c(a);
a.func();
b.func();
c.func();
return 0;
}
Причина для этого заключается в том, что я на самом деле пытаюсь реализовать Pattern Decorator (class B
имеет внутреннюю переменную myA
, которую я хочу декорировать), но я также хотел бы использовать некоторые из защищенных членов class A
при выполнении «декорированных» вычислений (в class B
и всехиз его подклассов).Следовательно, этот пример не является правильным примером декоратора (даже не простого).В примере я сосредоточился только на демонстрации проблемной функциональности (что я хочу использовать, но не могу).В этом примере используются даже не все классы / интерфейсы, необходимые для реализации шаблона Decorator (у меня нет абстрактного интерфейса базового класса , также унаследованного конкретными экземплярами базового класса как абстрактный интерфейс декоратора , который будет использоваться в качестве суперкласса для бетонных декораторов ).Я упоминаю декораторы только для контекста (причина, по которой я хочу указатель A*
).
В этом конкретном случае я не вижу особого смысла делать (мой эквивалент) int var
публичным (илидаже написание общедоступного метода получения) по двум причинам:
- , более очевидная причина: я не хочу, чтобы пользователи фактически использовали информацию напрямую (у меня есть некоторые функции, которыевернуть информацию, относящуюся и / или записанную в моих
protected
переменных, но не в само значение переменной) - переменная
protected
в моем случае гораздо труднее скопировать, чем int
(это2D std::vector
из double
с), и копирование его в экземпляр производного класса было бы излишне затратным по времени и памяти
Прямо сейчас у меня есть два разных способазаставить мой код делать то, что я от него хочу, но мне не нравится ни один из них, и я ищу концепцию C++
, которая на самом деле была предназначена для выполнения чего-то подобного (я не могу быть первымчеловек желать этого бытьhavior).
Что у меня есть и почему мне это не нравится:
1.объявляя все (соответствующие) унаследованные классы friend
s базовому классу:
class A{
....
friend class B;
friend class C;
};
Мне не нравится это решение, потому что оно заставит меня изменить мой базовый класс каждый раз, когда я пишу новый класс подкласса , и это именно то, чего я пытаюсь избежать.(Я хочу использовать только интерфейс «А» в основных модулях системы.)
2.приведение указателя A*
к указателю унаследованного класса и работа с ним
void B::func(){
B *uglyHack = static_cast<B*>(myA);
std::cout << uglyHack->var + 1 << std::endl;
}
Имя переменной довольно наводит на размышления относительно моих ощущений от использования этого подхода, но именно яиспользуя прямо сейчас.Поскольку я проектировал эти классы, я знаю, как быть осторожным и использовать только то, что фактически реализовано в class A
, рассматривая его как class B
.Но если кто-то еще продолжит работу над моим проектом, он может быть не очень знаком с кодом.Кроме того, приведение указателя переменной к чему-то, что я очень хорошо знаю, что это не просто чувствует чистое зло для меня.
Я пытаюсь сделать код этого проекта приятным ипродуман до мелочей, поэтому, если у кого-то есть какие-либо предложения относительно решения, которое время от времени не требует изменения базового класса или использования злых понятий, я был бы очень признателен.