是否可以使用抽象类,但FORCE实现类只包含抽象类中的公共方法?
我不关心私有方法是如何工作的,但是我想强制这些类只有一个公共方法。
例如,假设我有以下抽象类:
class MyObjectTransform
{
public:
virtual ~MyObjectTransform()
{
}
virtual MyObject transform(MyObject input) = 0;
};
然后我想强制从MyObjectTransform
继承的所有对象只有一个(构造函数除外)公共方法transform
。我不关心继承类有哪些私有方法。这可能吗?
更新 这里的目标是强制开发人员仅通过单个方法公开功能。例如,考虑这种情况:
class ATransform
{
private:
MyObject A_Stuff(MyObject input);
public:
override MyObject transform(MyObject input)
{
return this->A_stuff(input);
}
};
class BTransform
{
public:
MyObject B_Stuff(MyObject input);
override MyObject transform(MyObject input)
{
return this->B_stuff(input);
}
};
这里的问题是开发人员可以直接调用B_Stuff
。我想阻止这一点。
答案 0 :(得分:5)
不,你不能。派生类可以定义他们想要的任何公共成员函数。没有办法限制它。
<强>更新强>:
如果您不希望用户访问它,则将B_Stuff声明为私有。如果您希望从BTransform派生的类也可以使用它,则将其声明为 protected 。
class BTransform
{
private:
MyObject B_Stuff(MyObject input);
Public:
override MyObject transform(MyObject input)
{
return this->B_stuff(input);
}
};
但是你不能强迫用C ++语言将B_Stuff声明为私有或受保护。必须将其定义为政策。
答案 1 :(得分:4)
您已经在使用适用于此场景的机制:它是抽象基类!
这一点的重点在于,此层次结构中的所有类都旨在支持通过指向基类MyObjectTransform
的引用进行多态化。这样,用户不知道实现类具有哪些公共方法,因为他只能使用通过基类可用的方法:transform
。
如果您想更严格地强制执行此操作,请不要在标头中公开实现类的声明。隐藏BTransform
和ATransform
,并仅显示工厂函数和抽象基类。
std::unique_ptr<MyObjectTransform> makeATransform()
{
return { new ATransform };
}
std::unique_ptr<MyObjectTransform> makeBTransform()
{
return { new BTransform };
}
这样客户端/开发人员代码如下所示:
int main()
{
auto btransform = makeBTransform();
btransform->B_Stuff(input); // ERROR, MyObjectTransform doesn't have this member function.
btransform->transform(input); // FINE
}
用户只能在基类中使用一个公共方法。
当然有人可以将指针转换为BTransform*
,然后做任何他们想做的事情(前提是他们可以找出BTransform
的实际实现是什么,因为我们隐藏了它)。但是,没有绕过这样一个事实,即为了阻止public
方法被访问,你必须让它们private
,就像chmike写的那样。正如Herb Sutter所说:
C ++防止墨菲,而不是马基雅维利
答案 2 :(得分:1)
在C ++中,公共函数应该是非虚拟的,虚函数应该是私有的(析构函数除外)。应用此guideline会使您的问题完全消失,因为只有一个公共函数可供该类的客户调用:
class MyObjectTransform
{
public:
virtual ~MyObjectTransform()
{
}
MyObject transform(MyObject input) // non-virtual!
{
// can do extra stuff, e.g. check input for validity
doTransform(input);
}
private:
virtual MyObject doTransform(MyObject input) = 0;
};
class ATransform : public MyObjectTransform
{
private:
MyObject A_Stuff(MyObject input);
MyObject doTransform(MyObject input) override
{
return this->A_Stuff(input);
}
};
class BTransform : public MyObjectTransform
{
private:
MyObject B_Stuff(MyObject input);
MyObject doTransform(MyObject input) override
{
return this->B_Stuff(input);
}
};