C++ 在C+中设计ABC(抽象基类)的良好实践+;
在java中,我们可以定义不同的接口,然后我们可以为一个具体的类实现多个接口C++ 在C+中设计ABC(抽象基类)的良好实践+;,c++,design-patterns,abstract-class,C++,Design Patterns,Abstract Class,在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 {
// 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
必须包含太多的纯函数,该怎么办?有更好的办法吗
在C++中,一般来说,我们应该避免使用多重继承< /P>
与任何其他语言功能一样,您应该在适当的地方使用多重继承。接口通常被认为是多重继承的适当使用(例如,请参见COM)
ABC
的构造函数不需要保护——它不能直接构造,因为它是抽象的
ABC析构函数不应该声明为纯虚拟的(当然应该声明为虚拟的)。如果派生类不需要构造函数,则不应要求它们实现用户声明的构造函数
接口不应该有任何状态,因此也不应该有任何成员变量,因为接口只定义如何使用某些东西,而不是如何实现它
ABC
不应该有太多的成员函数;它应该具有所需的确切数字。如果有太多的接口,显然应该删除那些未使用或不需要的接口,或者将接口重构为几个更具体的接口
virtual void MethodOne(int /*i*/) = 0; // ";" not "{}" - just a declaration
尽管析构函数应该是虚拟的(或者在某些情况下是非虚拟的并且受保护的,但是将其虚拟化是最安全的),但是将析构函数变成纯函数并没有任何意义
不需要受保护的构造函数——它是抽象的,这一事实已经阻止了实例化,除非作为基类
好的ABC不应该包含成员变量,而应该将变量保存在子类中,这是真的吗
通常是的。这在接口和实现之间提供了一个清晰的分离
正如我在评论中指出的,如果ABC必须包含太多的纯函数怎么办?有更好的办法吗
接口应尽可能复杂,仅此而已。只有“太多”的功能是不必要的;在这种情况下,摆脱他们。如果界面看起来太复杂,它可能试图做不止一件事;在这种情况下,你应该能够把它分解成更小的接口,每个接口都有一个目的。 第一:为什么我们要避免C++中的多重继承?我从来没见过 一个没有广泛使用它的大型应用程序。继承自 多个接口是使用它的一个很好的例子 请注意,Java的
接口
在您想要使用时就被破坏了
通过契约编程,您必须使用抽象类,并且
他们不允许多重继承。但是,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++默认工作方式(类)
头中的定义,但源文件中的实现代码)。不确定实际代码是否与第一个示例块相似,但接口类中的方法声明需要
virtual
关键字;只有在最初声明为virtual
后,它才是可选的。是否编译?纯虚函数中0后面的花括号是一个错误MSDN对抽象类说:@AlessandroPezzato:这是正确的;不能在类的主体中定义纯虚拟成员函数。它可以在类的定义之外定义。然而,一些编译器(例如VisualC++,至少Visual C++ 2010 SP1)将接受代码。AlessandroPezzato,为什么MSDN不提供虚拟析构函数?RE 3:构造函数虚拟化没有错,但是…如果类是抽象的,并且没有
class OneAndTwo : public One, public Two
{
};
class ImplementsOneAndTwo : public OneAndTwo
{
virtual void doFunctionOne( int i );
virtual double doFunctionTwo();
public:
};