如有兴趣了解更多请关注我的个人博客https://07xiaohei.com/
纯虚函数和抽象类:
(一)概念:
-
纯虚函数:
纯虚函数是指在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后面加=0。
纯虚函数是一定要被继承的,它为各派生类提供了一个公共界面,方便了多态的使用,而且无需在基类中实现函数(有时这样的操作是不合理的)。
纯虚函数可以写实现,但不建议写。
纯虚函数格式:virtual 类型 函数名(参数表 )=0
-
抽象类:
一个具有纯虚函数的类被称为抽象类,也被称为接口类。
抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操作。
所以,派生类实际上刻画了一组派生类的操作接口的通用语义,这些语义能够传给派生类,派生类可以具体实现这些语义,也可以再将这些语义传给自己的派生类。
(二)抽象类的限制:
- 抽象类最重要的一点是无法实例化出对象。
- 抽象类的派生类也无法实例化出对象,除非其重写了基类的纯虚函数——不重写,该派生类仍为抽象类,重写后成为可以建立具体的对象的类。
- 抽象类创建抽象类的指针和引用,但其只能用来指向派生类的对象。
- 抽象类不能作为函数的返回类型。
- 抽象类不能作为传值参数类型。
- 不能建立抽象类型存储空间。
(三)接口继承和实现继承:
普通成员函数的继承就是实现继承,虚函数的继承就是接口继承。
派生类的成员函数通过实现继承来继承,可以直接使用;而虚函数通过接口继承只会继承接口,需要重写实现。
所以,如果不用多态,不要把函数写成虚函数。
(四)代码:
#include <iostream>
using namespace std;
//抽象类,不能创建对象,可以创建指针和引用
class AbstractClass {
public:
AbstractClass() {}
virtual ~AbstractClass() {}
//纯虚函数
virtual void toString() = 0;
//实现的纯虚函数,但是没必要实现
virtual void toString2() = 0 { cout << "toString2" << endl; }
};
//派生类继承抽象类
class SubClass : public AbstractClass {
public:
SubClass() : AbstractClass() {}
public:
~SubClass() {}
public:
//完成纯虚函数实现,可以创建对象
void toString() {
cout << "Sub::toString()" << endl;
}
void toString2() {
cout << "Sub::toString2()" << endl;
}
};
//同样继承,但是未全部实现,仍为抽象类
class SubClass2 :public AbstractClass
{
public:
SubClass2() : AbstractClass() {}
public:
~SubClass2() {}
public:
//完成部分纯虚函数实现,不能创建对象
void toString() {
cout << "SubClass2::toString()" << endl;
}
};
class SubClass3 :public SubClass2
{
public:
SubClass3() : SubClass2() {}
public:
~SubClass3() {}
public:
//toString的纯虚函数实现在SubClass2中实现了,此处可以不实现,也可以再次实现
//完成剩余部分的纯虚函数实现,可以创建对象
void toString2() {
cout << "SubClass3::toString2()" << endl;
}
};
class SubClass4 :public SubClass2
{
public:
SubClass4() : SubClass2() {}
public:
~SubClass4() {}
public:
//toString的纯虚函数实现在SubClass2中实现了,此处重写实现
//完成全部的纯虚函数实现,可以创建对象
void toString() {
cout << "SubClass4::toString()" << endl;
}
void toString2() {
cout << "SubClass4::toString2()" << endl;
}
};
//错误函数:不能将抽象类作为函数参数,也不能作为函数返回值。
//AbstractClass print(AbstractClass a) { return; }
int main(int argc, char** argv) {
//AbstractClass a;error:不允许使用抽象类类型的对象
cout << sizeof(AbstractClass) << endl; //为8,是虚指针
cout << sizeof(SubClass) << endl; //亦为8,也是虚指针,两者始终相同
SubClass s;
//SubClass2 s2; error:不允许使用抽象类类型的对象
SubClass3 s3;
SubClass4 s4;
AbstractClass& c = s;
AbstractClass* pc = &s;
c.toString();
pc->toString2();
pc = &s3;
pc->toString();
pc->toString2();
pc = &s4;
pc->toString();
pc->toString2();
return 0;
}
//Sub::toString()
//Sub::toString2()
//SubClass2::toString()
//SubClass3::toString2()
//SubClass4::toString()
//SubClass4::toString2()
异质链表:
(一)概念:
用基类类型指针(抽象类类型指针也可以),可以生成一个连接不同派生类对象的动态链表。
每个结点指针可以指向类层次中不同的派生类对象,这种结点类型不相同的链表被称为异质链表。
(二)限制:
- 链表节点的类类型不止一个时,这些类必须是继承关系。
- 可以是多层继承关系,但是必须有一个基类是所有类的基类(类似于树的根节点)。
- 声明节点时的指针必须是基类类型,创建节点时new后面的类型可以是基类或者是派生类。
- 输出方法可以是各个类的自己成员函数或友元函数,或者是另写一个输出方法。
(三)代码:
#include <iostream>
using namespace std;
class Person {
protected:
string name;
int age;
public:
static Person* head;
static Person* tail;
Person* next;
public:
Person(string n = "", int a = 0) :name(n), age(a) { cout << "Person()" << endl; }
virtual void insert() { //将新结点加入链表
//head、tail 是静态的,就相当于全局变量;
if (tail == NULL)
head = tail = this;
else {
tail->next = this;
tail = this;
tail->next = NULL;
}
}
virtual void display() {
cout << " name = " << name << endl;
cout << " age = " << age << endl;
}
virtual ~Person() {
cout << "~person()" << endl;
}
};
Person* Person::head = NULL;
Person* Person::tail = NULL;
//Student中增加了一个score
class Student : public Person {
float score;
public:
Student(string n, int a, float f) :Person(n, a),score(f) {
cout << "Student()" << endl;
}
void display() {
cout << "display student:" << endl;
Person::display();
cout << " score =" << score << endl;
}
~Student()
{
cout << "~Student()" << endl;
}
};
//Teacher中增加了salary
class Teacher : public Person {
private:
double salary;
public:
Teacher(string n, int a, double salary) :Person(n, a) {
this->salary = salary;
}
void display() {
cout << endl << "display teacher:" << endl;
Person::display();
cout << " Salary =" << salary << endl;
}
~Teacher() {
cout << "~Teacher()" << endl;
}
};
Student* CreateStudent() {
string name;
int age;
float score;
cout << "Student name:" << endl;
cin >> name;
cout << "age: " << endl;
cin >> age;
cout << "score: " << endl;
cin >> score;
Student* p = new Student(name, age, score);
return p;
}
int main()
{
Teacher* t1 = new Teacher("最萌斌斌姐", 25, 100);
Student* s1 = new Student("wlh", 21, 99);
Student* s2 = new Student("zk", 21, 60);
Teacher* t2 = new Teacher("wdg", 45, 20);
Student* ps = CreateStudent();
cout << endl << "Person list" << endl;
t1->insert();
s1->insert();
s2->insert();
t2->insert();
ps->insert();
cout << endl;
cout << "dispay Person list:" << endl;
Person* p;
p = Person::head;
while (p != NULL) {
p->display();
cout << endl;
p = p->next;
}
cout << endl;
cout << "delete whole list" << endl;
p = Person::head;
while (p != NULL)
{
Person::head = p->next;
delete p;
p = Person::head;
}
Person::tail = NULL;
return 0;
}
/*运行结果
Person()
Person()
Student()
Person()
Student()
Person()
Student name :
zzh
age :
21
score :
100
Person()
Student()
Person list
dispay Person list :
display teacher :
name = 最萌斌斌姐
age = 25
Salary = 100
display student :
name = wlh
age = 21
score = 99
display student :
name = zk
age = 21
score = 60
display teacher :
name = wdg
age = 45
Salary = 20
display student :
name = zzh
age = 21
score = 100
delete whole list
~Teacher()
~person()
~Student()
~person()
~Student()
~person()
~Teacher()
~person()
~Student()
~person()*/