在C ++中,假设我有一个类 Derived
,它实现了一个接口类 BaseInterface
,其中 {{1} } 只有纯虚函数和虚析构函数:
BaseInterface
class BaseInterface
{
public:
virtual void doSomething() = 0;
~BaseInterface(){}
};
class Derived : public BaseInterface
{
public:
Derived() {}
~Derived(){}
protected:
virtual void doSomething();
private:
int x;
};
类层次结构之外的任何类都不应直接调用Derived
,即只能通过Derived::doSomething()
类以多态方式访问它。为了执行此规则,我已对BaseInterface
进行了保护。这很有效,但我正在寻找关于这种方法的意见/赞成。
谢谢!
肯
答案 0 :(得分:9)
我认为您正在寻找非虚拟接口(NVI)模式:调用受保护或私有public
实现的virtual
非虚拟接口:
class BaseInterface
{
public:
virtual ~BaseInterface(){}
void doSomething() { doSomethingImpl(); }
protected:
virtual void doSomethingImpl() = 0;
};
class Derived : public BaseInterface
{
public:
Derived() {}
virtual ~Derived(){}
protected:
virtual void doSomethingImpl();
private:
int x;
};
答案 1 :(得分:3)
如果它是界面的一部分,为什么你不希望用户调用它?请注意,实际上,他们可以调用它:static_cast<BaseInterface&>(o).doSomething()
只是说o.doSomething()
的一种尴尬方式。 使用接口有什么意义...如果对象满足界面,那么你应该能够使用它,还是我错过了什么?
由于您实际上并没有阻止任何人调用这些方法,因此我没有看到使代码更复杂的问题(类的类和用户)没有特别的原因。请注意,这与非虚拟接口完全不同,因为在这个成语中,虚拟功能无法公开访问(在任何级别),而在您的情况下,目的是允许访问,并使其变得麻烦。
答案 2 :(得分:2)
您正在做的事情也在标准ISO / IEC 14882:2003(E)11.6.1中提到并且相信您是正确的。除了事实之外,在给定的示例中,成员函数不是纯虚拟的。它应该适用于纯虚函数,AFAIK。
虚函数的访问规则(第11节)由其声明确定,不受稍后覆盖它的函数规则的影响。
[Example:
class B
{
public:
virtual int f();
};
class D : public B
{
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public,
// D::f() is invoked
pd->f(); // error: D::f() is private
}
—end example]
使用用于表示的表达式类型在呼叫点检查访问 调用成员函数的对象(上例中为B *)。成员函数在定义它的类中的访问(上例中的D)通常是未知的。
答案 3 :(得分:1)
关键是代码的其余部分。只接受BaseInterface *作为任何需要doSomething()调用的方法的参数。客户端程序员被迫从接口派生出来以编译代码。
答案 4 :(得分:0)
这对我没有意义。无论您调用哪个指针doSomething()
,您仍然可以使用大多数派生类中定义的方法。请考虑以下情形:
class BaseInterface
{
public:
virtual void doSomething() = 0;
~BaseInterface(){}
};
class Derived : public BaseInterface
{
public:
Derived() {}
~Derived(){}
virtual void doSomething(){}
private:
int x;
};
class SecondDerived : public Derived
{
public:
SecondDerived() {}
~SecondDerived(){}
private:
int x;
};
int main(int argc, char* argv[])
{
SecondDerived derived;
derived.doSomething(); //Derived::doSomething is called
BaseInterface* pInt = &derived;
pInt->doSomething(); //Derived::doSomething is called
return 0;
}