【C++程序设计基础】Chap9虚函数与多态性笔记

文章讨论了C++中的类指针关系,包括基类指针引用派生类对象和派生类指针引用基类对象的情况。重点讲述了虚函数的概念,如何通过虚函数实现运行时多态性,以及虚函数的重载特性。此外,还提到了虚析构函数的作用,防止在删除基类指针指向的派生类对象时出现内存泄漏。最后,文章通过实例介绍了纯虚函数和抽象类的应用,以及如何构建动态异质链表。
摘要由CSDN通过智能技术生成

静态联编

静态联编:又称早期联编,程序运行之前完成匹配、连接,如函数调用、重载函数
动态联编:联编在运行时进行,又称晚期联编,在编译阶段不能知道逻辑分支的选择,如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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值