组成
- 基类构成的子对象:由基类的非静态成员函数组成
- 派生类的部分:派生类的非静态成员函数。
:::info why非静态,静态的会怎么样? :::
- 派生类在声明前,基类必须已经定义;
- 必须为每个纯虚函数提供实现
- 虚函数类外实现可以不加virtual关键字
基类
class num_sequence {
public:
num_sequence() {
cout << " create a num sequence" << endl;
}
virtual ~num_sequence() {
cout << "~num_sequence has been called" << endl;
}
virtual int elem(int pos) const= 0;
virtual const string what_am_i() const = 0;
static int max_elems(){
return _max_elems;
}
virtual ostream& print(ostream& = cout) const = 0;
protected:
virtual void gen_elems(int pos) const = 0;
// const指针指向自认为const的一个对象, 这个对象不能通过const指针进行修改,
//但可以通过其他方式进行修改
bool check_integrity(int pos) const{
if(pos <=0 || pos >_max_elems) {
cerr << "Invalid position: " << pos << endl;
return false;
}
return true;
}
const static int _max_elems = 1024; // 最大元素个数
};
派生类:
class Fibonacci : public num_sequence {
public:
Fibonacci(int len = 1, int beg_pos = 1): _length(len), _beg_pos(beg_pos){
cout << "create a Fibonacci sequence" << endl;
}
virtual int elem(int pos) const ; // 子类类中声明virtual时, 应当和父类保持精确一致
virtual ostream& print(ostream &os=cout) const;
virtual const string what_am_i() const{
cout << " I am Fibonacci sequence" << endl;
}
int length() const {
return _length;
}
int beg_pos() const{
return _beg_pos;
}
~Fibonacci() {
cout << "~Fibonacci has been called" << endl;
}
protected:
virtual void gen_elems(int pos) const;
int _length; // 长度
int _beg_pos; // 起始位置
static vector<unsigned int> _elems; // 元素容器
};
若是用基类的指针调用派生类中为声明为virtual的成员函数,则会失败ps->length()
;
解决方法:要么在基类中将其声明为纯虚函数,要么将此函数也包括在基类中;
:::tips
如果以一个衍生类指针指向一个基础类对象,必须先做强制转型动作(explicit cast),这种做法很危险,也不符合语法习惯,在程序设计上也会给程序员带来困扰。(一般不会这么去定义)
:::
class scope运算符的遮掩作用
通过class scope运算符,可以明确告诉编译器我想调用那一份函数实例,因此虚拟机制可以被遮掩
int Fibonacci::
elem(int pos)const{
if(pos>_elems.size())
Fibonacci::gen_elems(pos);//此时明确指明调用哪一份函数实例!
return _elems[pos-1]
}
抽象类
:::success
抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。
(1)抽象类的定义: 称带有纯虚函数的类为抽象类。
(2)抽象类的作用: 抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。所以派生类实际上刻画了一组子类的操作接口的通用语义,这些语义也传给子类,子类可以具体实现这些语义,也可以再将这些语义传给自己的子类。
(3)使用抽象类时注意:抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。如果派生类中没有重新定义纯虚函数,而只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。如果派生类中给出了基类纯虚函数的实现,则该派生类就不再是抽象类了,它是一个可以建立对象的具体的类。
:::