类围绕成员变量进行设计,构造函数围绕成员变量构建类,成员函数围绕成员变量展开
总之,在类的声明与实现中,成员变量居于中心的位置。 -
普通成员函数与虚函数
在一个抽象基类的内部可以有三种形式成员函数:
- 普通成员函数
所有派生类共享的函数实现,可以不给出实现(其实这样做没有意义),但当调用时自然会发生解析错误。 - 虚函数
必须给出实现,否则子类无法进行函数的重写。不同的子类可对其进行部分重写,根据需求。 - 纯虚函数
全部子类如果想成为能够实例化对象的类,必须实现父类的全部纯虚函数,否则子类仍是抽象类无法实例化对象。
class Base
{
public:
void foo(){} // 普通函数
virtual void fooA();
// 虚函数,交由DerivedA 实现
{
throw std::exception("cannot be called");
// 抛异常的目的是为了禁止DerivedB对象试图去调用(设计上)只能交由DerivedA对象调用的函数时
}
virtual void fooB();
// 虚函数,交由DerivedB实现
{
throw std::exception("cannot be called")
// 抛异常的目的是为了禁止DerivedA对象试图去调用(设计上)只能交由DerivedB对象调用的函数时
}
virtual void f() = 0;
// 纯虚函数
}
class DerivedA :public Base
{
public:
void fooA()
{ cout << "DerivedA::fooA()" << endl;}
void f(){}
}
class DerivedB :public Base
{
public:
void fooB()
{ cout << "DerivedB::fooB()" << endl;}
void f() {}
}
int main(int, char**)
{
DerivedA da;
DerivedB db;
da.foo();
db.foo(); // 调用父类的非虚成员函数
da.fooB(); // 抛异常
da.fooA(); // 多态,调用DerivedA的实现
db.fooA(); // 抛异常,
db.fooB(); // 多态,调用DerivedB的实现
Base* b = new DerivedA;
b->fooA(); // 多态
b->fooB(); // 抛异常
b = new DerivedB;
b->fooB(); // 多态
b->fooA(); // 抛异常
return 0;
}
使用UML类图,
即可以在设计好UML类图的前提之下进行代码的编写,也可边写代码,边设计类图。
从成员变量开始一个类的设计
成员函数围绕成员变量进行展开;
多个重载版本
可以有不同的重载版本(客户端调用的方便),实现时然后相互调用(为了编写代码的便捷)
这种重载不仅对于类的成员函数之间是如此,不同的全局函数也是如此,不妨以STL的算法中的sort
为例进行展示: