我有一个案例,我找不到合适的解决方案。我需要有模板基类和一个对该基类做一些工作的管理器类。这是代码
class Base;
class Manager
{
public:
void DoSomethingTo(Base * bclass)
{
if(bclass->PrivateVar == 0)
// Some code
}
}
class Base
{
protected:
int PrivateVar;
friend class Manager;
};
template<class T>
class TempBase : public Base
{
private:
Manager * man;
public:
void DoWork()
{
PrivateVar = 0;
man->DoSomethingTo(this);
}
}
我的问题是PrivateVar变量实际上必须是TempBase的私有,并且不能从TempBase派生的类访问,但由于我无法将其指针传递给Manager::DoSomethingTo()
,我必须从Base类和Base类派生它必须拥有PrivateVar。因为我在TempBase中使用PrivateVar,所以它不能是Base的私有,这使得它可以从TempBase的子类访问。
如何编写TempBase类,以便PrivateVar是私有成员,而可以从Manager::DoSomethingTo()
访问它?
由于
答案 0 :(得分:2)
首先,让我们开始火焰战:
类的属性永远不会是
protected
的原因。它应该是private
(在大多数情况下)或者可能是某些角落public
。请注意,因为每个派生类都会看到protected
属性,protected
只会带来一种错误的安全感:一个人无法控制protected
属性的任何不变量,所以它基本上是{{1}一个,带有注释不要触摸。
既然已经说完了,我建议只需将其更改为:
public
通过将测试的责任委托给变量的所有者,我们会轻轻地绕过所有的担忧。当然,如果我们需要多个类以类似的方式运行,那么我们可以在class Base {};
template <typename T> class TBase;
class DoKey { template <typename T> friend class TBase; DoKey(); };
class Manager
{
public:
void DoSomethingTo(Base& base, DoKey const& key);
};
template <typename T>
class TBase: public Base
{
public:
void Do()
{
Manager manager;
if (PrivateVar == 0) { manager.DoSomething(*this, DoKey()); }
}
private:
int PrivateVar;
};
中引入纯虚void ShouldIDoSomething() const
并在Base
的方法中检查它。
答案 1 :(得分:1)
删除Base
内的访问保护,然后私下继承。
class Manager
{
public:
void DoSomethingTo(struct Base * bclass);
};
struct Base
{
int PrivateVar;
};
void Manager::DoSomethingTo(struct Base * bclass)
{
if(bclass->PrivateVar == 0)
; // Some code
}
template<class T>
class TempBase : private Base
{
private:
Manager * man;
public:
void DoWork()
{
PrivateVar = 0;
man->DoSomethingTo(this);
}
};
答案 2 :(得分:0)
您可以将受保护的成员函数放入Base本身:
class Base
{
protected:
void sendPrivateVarToManager( Manager& manager )
{
manager.DoSomethingToPrivateVar( privateVar );
}
};
由于Base不是模板,实现实际上可以放在Base之外。
您的另一个问题是您希望privateVar存在于Base中,对TempBase是可见的,而不是层次结构中的任何其他内容。您可以将其移动到TempBase中,在这种情况下,您也可以将sendPrivateVarToManager放在该类中,尽管您必须实现它,或者将privateVar作为参数传递给它。你的另一个选择是让TempBase成为Base的朋友,但这似乎是错误的。我不确定为什么TempBase需要访问。
答案 3 :(得分:0)
您可以将PrivateVar
设为私有,并将TempBase
和Manager
朋友设为Base
。见here。请注意,此代码不是最干净的代码。
答案 4 :(得分:0)
我认为我可以将一个公共的纯虚函数放到Base来检索PrivateVar,同时将PrivateVar保存在TempBase中。
class Manager
{
public:
void DoSomethingTo(Base * bclass)
{
if(bclass->GetPrivateVar() == 0)
// Some code
}
}
class Base
{
private:
virtual int GetPrivateVar() = 0;
friend class Manager;
};
template<class T>
class TempBase : public Base
{
private:
Manager * man;
int PrivateVar;
int GetPrivateVar() {return PrivateVar;}
public:
void DoWork()
{
PrivateVar = 0;
// Some code
man->DoSomethingTo(this);
// Some code
}
friend class Manager;
}