文章目录
静态联编
静态联编:又称早期联编,程序运行之前完成匹配、连接,如函数调用、重载函数
动态联编:联编在运行时进行,又称晚期联编,在编译阶段不能知道逻辑分支的选择,如switch、if
类体系中,普通成员函数的重载有两种形式:
1、同一类中重载
2、基类成员函数在派生类中重载
第二种形式的区分调用方法:
1、根据参数特征
2、作用域运算符::
3、根据对象所属的类,基类对象调用基类函数,派生类对象调用派生类函数。
类指针的关系
基类指针引用派生类对象(注:引用并非&运算符,而是指对对象的读写等操作)
直接用基类指针访问派生类对象,则只能访问派生类对象中的基类成员,而不能访问派生类特有的数据成员。
若试图引用派生类成员,则需要通过强制类型转换将基类指针转换为派生类指针,或者采用虚函数(在后文阐述)
类型转换是基类指针调用派生类特有成员的办法
e.x. 强制转换基类指针引用派生类对象示例
#include<iostream>
using namespace std;
class A
{
public:
int a;
};
class B:public A
{
public:
int b;
};
int main()
{
A* ap;
((B*)ap)->b;//由于优先级制约,此处括号不可去
(*((B*)ap)).b;
}
派生类指针引用基类对象
必须通过强制类型转换,但是强制类型转换只改变临时类型(可以理解为右值),不改变指针原类型。
e.x.
#include<iostream>
using namespace std;
class A
{
public:
int a;
};
class B
{
public:
int b;
};
int main()
{
B* bp;
((A*)bp)->a;
bp->a;//非法,bp仍为B*型
}
虚函数
定义:冠以关键词virtual的成员函数
调用虚函数时,采用虚函数解释机制,即基类指针根据**地址(当前指向)**调用不同类版本的成员函数
当基类运用关键词virtual说明后,派生类定义的重载函数默认为虚函数(即使派生类中没有virtual,一虚全虚)
虚函数必须是类的成员函数,不能为构造函数、普通函数、静态成员函数、友元函数,但可以是另一个类的友元,即A类的虚函数可以被A的友元类B调用
虚函数的重载特性
重载虚函数要求:函数名、返回类型、参数个数、参数类型和顺序完全相同,若参数表不同,会被认为是一般函数重载
虚函数是只由this指针类型区分接口的函数
虚析构函数
出于操作需要,一般析构函数都被定义为虚析构函数
针对的问题:用基类指针建立派生类动态对象时,delete只能调用基类的析构函数,而没有完成派生类的析构,会导致内存泄漏
将基类析构函数说明为虚析构函数,用delete删除基类指针时会在执行派生类的析构函数后自动执行基类的析构函数。
纯虚函数与抽象类
具有纯虚函数的基类称为抽象类
纯虚函数是在基类中声明的虚函数,它在该基类中没有实现定义,要求所有派生类必须都定义自己的版本。若派生类不定义基类的纯虚函数,则无法构建自己的对象。
纯虚函数的说明形式:
virtual 类型 函数名(参数表)= 0;
定义了纯虚函数实现版本的派生类称为具体类
对抽象类的限制:
1、规范上只能用作其他类的基类,但实践上可用作继承类
2、不能建立对象
3、不能用作参数类型、函数返回类型或显式类型转换
4、只能使用抽象类的指针和引用
含有虚函数的类至少有一个虚函数表指针,这个指针会开辟存储空间
应用:异质链表
异质,即链表中指针指向的类型不同,通过虚函数我们可以根据this接口灵活地调用对应派生类的函数
指针数组型
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
class A
{
public:
int a;
A(int n = 1) { a = n; }
virtual void print() { cout << a << '\n';}
};
class AB :virtual public A
{
public:
int b;
AB(int n) { b = n; }
virtual void print() { cout << "b=" << b << '\n'; }
};
class AC :virtual public A
{
public:
int c;
AC(int n) { c = n; }
virtual void print() { cout << "c = " << c << '\n'; }
};
int main()
{
A* a[1005];//指针数组利于动态分配存储空间,并根据this指针接口调用相应函数
a[0] = new AB(3);
a[1] = new AC(4);
a[0]->print();
a[1]->print();
return 0;
}
//output:
//b=3
//c = 4
动态异质链表
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
class A
{
public:
int a;
A* next;
A(int n = 1) { a = n; }
virtual void print() { cout << a << '\n';}
friend void addfront(A*& h, A*& ptr)//此处将友元函数在类中定义仅为实验,请勿模仿
{
ptr->next = h;
h = ptr;
}
};
class AB :virtual public A
{
public:
int b;
AB(int n) { b = n; }
virtual void print() { cout << "b=" << b << '\n'; }
};
class AC :virtual public A
{
public:
int c;
AC(int n) { c = n; }
virtual void print() { cout << "c = " << c << '\n'; }
};
int main()
{
A* head = NULL,*ptr;
ptr = new AB(3);
addfront(head, ptr);
head->print();
ptr = new AC(4);
addfront(head, ptr);
head->print();
}
//output:
//b=3
//c = 4