在java中,我们可以定义不同的接口,然后我们可以为具体的类实现多个接口。
// Simulate Java Interface in C++
/*
interface IOne {
void MethodOne(int i);
.... more functions
}
interface ITwo {
double MethodTwo();
... more functions
}
class ABC implements IOne, ITwo {
// implement MethodOne and MethodTwo
}
*/
在C ++中,一般来说,我们应该避免使用多重继承,尽管多继承确实在某些情况下具有优势。
class ABC {
public:
virtual void MethodOne(int /*i*/) = 0 {}
virtual double MethodTwo() = 0 {}
virtual ~ABC() = 0 {}
protected:
ABC() {} // ONLY ABC or subclass can access it
};
问题1 >基于ABC
的设计,我应该改进其他任何事情,以使其成为一个体面的ABC吗?
问题2 >良好的ABC
不应该包含成员变量,而变量应该保存在子类中吗?
问题3 >正如我在评论中指出的那样,如果ABC
必须包含太多纯函数,该怎么办?还有更好的方法吗?
答案 0 :(得分:9)
在C ++中,一般来说,我们应该避免使用多重继承
与任何其他语言功能一样,您应该在适当的地方使用多重继承。接口通常被认为是多重继承的适当使用(例如,参见COM)。
ABC
的构造函数不需要保护 - 它不能直接构造,因为它是抽象的。
不应将ABC
析构函数声明为纯虚拟(当然,它应声明为虚拟)。如果不需要派生类,则不应要求派生类实现用户声明的构造函数。
接口不应该有任何状态,因此不应该有任何成员变量,因为接口只定义了如何使用某些东西,而不是如何实现它。
ABC
永远不应该有太多的成员函数;它应该具有所需的数量。如果太多,您显然应该删除那些未使用或不需要的,或者将接口重构为几个更具体的接口。
答案 1 :(得分:9)
如果这是一个界面,那么最好没有任何变量。否则它将是一个抽象基类而不是接口。
太多的纯函数都可以,除非你能用较少的纯函数来完成它。
答案 2 :(得分:4)
根据ABC的设计,我应该改进其他任何东西,以使其成为一个体面的ABC吗?
你有几个语法错误。出于某种原因,您不允许在类定义中放置纯虚函数的定义;无论如何,你几乎肯定不想在ABC中定义它们。所以声明通常是:
virtual void MethodOne(int /*i*/) = 0; // ";" not "{}" - just a declaration
将析构函数设置为纯粹没有任何意义,尽管它应该是虚拟的(或者,在某些情况下,非虚拟和受保护 - 但最安全的是使它成为虚拟的)。
virtual ~ABC() {} // no "= 0"
不需要受保护的构造函数 - 它是抽象的事实已经阻止了实例化,除了作为基类。
一个好的ABC不应该包含成员变量,而变量应该保存在子类中吗?
通常,是的。这样可以在界面和实现之间实现清晰的分离。
正如我在评论中指出的那样,如果ABC必须包含太多纯函数,该怎么办?还有更好的方法吗?
界面应该尽可能复杂,而不是更多。只有一些是不必要的,只有“太多”的功能;在这种情况下,摆脱它们。如果界面看起来太复杂,它可能会尝试做多件事;在这种情况下,您应该能够将其分解为更小的接口,每个接口都有一个目的。
答案 3 :(得分:3)
首先:为什么我们应该避免C ++中的多重继承?我从来没见过 一个大的应用程序,没有广泛使用它。继承自 多个接口是使用它的好例子。
请注意,只要您想使用,Java的interface
就会被破坏
通过合同编程,你坚持使用抽象类,并且
他们不允许多重继承。但是,在C ++中,它很简单:
class One : boost::noncopyable
{
virtual void doFunctionOne( int i ) = 0;
public:
virtual ~One() {}
void functionOne( int i )
{
// assert pre-conditions...
doFunctionOne( i );
// assert post-conditions...
}
};
class Two : boost::noncopyable
{
virtual double doFunctionTwo() = 0;
public:
virtual ~Two() {}
double functionTwo()
{
// assert pre-conditions...
double results = doFunctionTwo();
// assert post-conditions...
return results;
}
};
class ImplementsOneAndTwo : public One, public Two
{
virtual void doFunctionOne( int i );
virtual double doFunctionTwo();
public:
};
或者,你可以有一个复合界面:
class OneAndTwo : public One, public Two
{
};
class ImplementsOneAndTwo : public OneAndTwo
{
virtual void doFunctionOne( int i );
virtual double doFunctionTwo();
public:
};
并从中继承,这是最有意义的。
这或多或少是标准的习语;在没有的情况下 可以想象是界面中的任何前置或后置条件(通常是 调用反转),虚函数可能是公共的,但一般来说, 他们将是私人的,因此你可以强制执行预先和 后置条件。
最后,请注意在很多情况下(特别是如果上课 代表一个值),你将直接实现它,而不是 接口。与Java不同,您不需要单独的界面来维护 在类的不同文件中实现 定义 - 这是C ++默认工作的方式(使用类 标题中的定义,但源文件中的实现代码。)