首先,我知道我做不到,我认为这不是一个重复的问题(
this和
this问题处理同样的问题,但他们只想解释为什么它不起作用).
所以,我有类和继承的类似概念,我会以某种方式优雅地想要做一些被禁止的事情.这是一个非常简单的代码片段,反映了我想要做的事情:
#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;
}
这样做的原因是我实际上试图实现一个Decorator Pattern(B类有我想要装饰的myA内部变量),但是我还想使用A类的一些受保护成员来做“装饰“计算(在B类及其所有子类中).因此,这个例子不是装饰器的正确例子(甚至不是简单的装饰器).在这个例子中,我只专注于演示有问题的功能(我想要使用但我不能).在这个例子中,甚至没有实现Decorator模式所需的所有类/接口(我没有抽象的基类接口,由具体的基类实例继承,以及抽象装饰器接口,用作超类)用于混凝土装饰器).我只提到装饰器的上下文(我想要一个A *指针的原因).
在这种特殊情况下,我认为制作(相当于)int var public(甚至编写一个可公开访问的getter)有两个原因:
>更明显的一个,我不希望用户直接实际使用信息(我有一些函数返回与我的受保护变量相关和/或写入的信息,但不是变量值本身)
>在我的情况下,受保护的变量比int更复杂(它是2D std :: vector of double),并且将其复制到派生类的实例中会不必要地浪费时间和内存
现在,我有两种不同的方式让我的代码做我想做的事情,但我不喜欢它们,我正在寻找一个实际上用于做这类事情的C概念(我不能成为第一个渴望这种行为的人).
到目前为止我有什么,为什么我不喜欢它:
1.将所有(相关的)继承类的朋友声明为基类:
class A{
....
friend class B;
friend class C;
};
我不喜欢这个解决方案,因为每次我编写一个新的子类时它都会强迫我修改我的基类,这正是我想要避免的. (我想在系统的主要模块中只使用’A’接口.)
2.将A *指针转换为继承类的指针并使用它
void B::func(){
B *uglyHack = static_cast<B*>(myA);
std::cout << uglyHack->var + 1 << std::endl;
}
变量名对我使用这种方法的感觉很有启发性,但这是我现在正在使用的那个.因为我设计了这个类,所以我知道如何小心并且只使用A类中实际实现的东西,同时将它作为B类处理.但是,如果其他人继续我的项目工作,他可能不是这样熟悉代码.另外,将一个变量指针投射到我非常清楚的事情中,这对我来说不仅仅是纯粹的邪恶.
我试图让这些项目的代码尽可能干净整洁,所以如果有人对解决方案有任何建议,不需要时不时地修改基类或使用邪恶的概念,我会非常感谢欣赏它.
最佳答案 我相信您可能想重新考虑设计,但是我可以如何访问该成员的具体问题的解决方案?可能:
class A{
protected:
int var;
static int& varAccessor( A& a ) {
return a.var;
}
};
然后在派生类型中调用受保护的访问者通过引用传递成员对象:
varAccessor( this->myA ) = 5;
现在,如果您正在考虑装饰器模式,我认为这不是可行的方法.
混淆的根源在于大多数人没有意识到类型有两个独立的接口,即面向用户的公共接口和实现提供者的虚拟接口(即派生类型),因为在许多情况下,功能都是公共的和虚拟的(即该语言允许绑定两个语义不同的接口).在Decorator模式中,您使用基接口来提供实现.继承是存在的,因此派生类型可以通过一些实际工作(装饰)为用户提供操作,然后将工作转发到实际对象.继承关系不是通过受保护元素以任何方式访问实现对象的,并且这本身就很危险.如果传递一个派生类型的对象,该对象具有关于该受保护成员的更严格的不变量(即对于类型为X的对象,var必须是奇数),您正在采用的方法将让装饰器(各种类型)打破不变量应该只是装饰的那种X型.