C++虚函数和多态

虚函数和虚函数表

什么是虚函数?

用virtual修饰的成员函数。

什么是虚函数表?

实质上就是函数指针,存储所有虚函数的首地址(函数名)。

#include<iostream>
using namespace std;
class Girl {
public:
protected:
	void print() {
		cout << "普通函数" << endl;//普通函数对类的大小无影响
	}
	virtual void printData1() {
		cout << "虚函数1" << endl;
	}
	virtual void printData2() {
		cout << "虚函数2" << endl;//虚函数对类的大小增加一个指针
	}
};
void testVirtual() {
	//C语言不允许存在空的结构体,但是C++允许
	cout << sizeof(Girl) << endl;//空的类或者结构体,占用一个字节
	Girl girl;
	
	int** vptr =(int**) &girl;
	typedef void(*PF)();
	PF pf;
	pf = (PF)vptr[0][0];
	pf();
	pf = (PF)vptr[0][1];
	pf();
}
int main() {
	testVirtual();
	return 0;
}

虚函数和多态

虚函数和多态一定是公有继承

多态定义:同一个调用(行为)所导致的不同结果

多态的必要原则:

1.必须父类存在虚函数

2.子类必须采用共有继承

3.必须存在指针的引用(使用)

#include<iostream>
using namespace std;
class Man {
public:
	void WC1() {
		cout << "男人上厕所" << endl;
	}
	virtual void WC2() {
		cout << "龌龊男人上厕所" << endl;
	}
protected:

};
class Woman:public Man {
public:
	void WC1() {
		cout << "女人上厕所" << endl;
	}
	void WC2() {//子类有无virtual无所谓
		cout << "女人上厕所" << endl;
	}
protected:

};
void testVirtual() {
	//正常访问不存在多态
	Man man;
	man.WC1();
	man.WC2();
	Woman woman;
	woman.WC1();
	woman.WC2();
	cout << "指针访问,正常赋值" << endl;
	Man* pm = new Man;
	pm->WC1();
	pm->WC2();
	Woman* pw = new Woman;
	pw->WC1();
	pw->WC2();
	cout << "指针访问,非正常赋值:子类对象初始化父类指针" << endl;
	Man* pman = new Woman;
	pman->WC1();	//不是虚函数,没有virtual看指针类型,调用父类
	pman->WC2();	//是虚函数,有virtual看对象类型,可以实现父类调用子类的方法
	pman = new Man;
	pman->WC2();	//两种调用同一个函数方法,结果不同,多态
}	
//可以实现统一接口功能
void printInfo(Man* parent) {
	parent->WC1();
	parent->WC2();
}

//可以实现统一接口功能,降低耦合,用增加代码而减少修改源代码

class Shape {
public:
	virtual void Draw() {
		cout << "绘制过程" << endl;
	}
protected:

};
class Rect :public Shape {
public:
	void Draw() {
		cout << "画矩形" << endl;
	}
protected:

};
class Circle :public Shape {
public:
	void Draw() {
		cout << "画圆" << endl;
	}
protected:
};

class Tool {
public:
	void draw(Shape* parent) {
		parent->Draw();
	}
};
int main() {
	testVirtual();
	printInfo(new Woman);//new一个临时对象,函数本身形参是父类指针,但是也可以传入子类对象。
	Tool* pTool = new Tool;
	pTool->draw(new Circle);
	pTool->draw(new Rect);
	return 0;
}

纯虚函数和ADT过程

纯虚寒是是一种特殊的虚函数,只是纯虚函数没有函数体;

virtual void print()=0;//一定是再类中

抽象类:具有至少一个纯虚函数的类,称为抽象类。

1.抽象类不能构建对象

2.抽象类可以构建对象指针

父类纯虚函数如果没有被重写(实现)无论被继承多少次任然是纯虚函数

#include<iostream>
using namespace std;
class Parent {
public:
	virtual void print() = 0;
protected:
};
void testAbstract() {
	//Parent object;抽象类不能构建对象
	Parent* parent = nullptr;//可以构建对象
}
//纯虚函数就是做ADT(abstract data type抽象数据类型)过程;把所有框架搭建好
//stack 栈
class stack {
public:
	//父类中所有操作描述好
	virtual void push(int data) = 0;
	virtual void pop() = 0;
	virtual int top()const = 0;
	virtual bool empty()const = 0;
	virtual int size()const = 0;
};
//子类想要创建对象,必须重写父类的纯虚函数
//ADT具有强迫性,所有子类重写函数必须和父类一模一样
class arrayStack :public stack {
public:
	void push(int data) {
	
	}
	void pop() {
	
	}
	int top()const {
		return 1;
	}
	bool empty()const {
		return true;
	}
	int size()const {
		return 1;
	}
protected:
	int* array;
};
struct Node {
	int data;
	Node* next;
};
class listStack :public stack {
public:
	void push(int data) {

	}
	void pop() {

	}
	int top()const {
		return 1;
	}
	bool empty()const {
		return true;
	}
	int size()const {
		return 1;
	}
protected:
	Node* headNode;
};
void testStack(stack* pStack) {
	pStack->push(1);
	while (!pStack->empty())
	{
		cout << pStack->top();
		pStack->pop();
	}
}
//父类纯虚函数如果没有被重写(实现)无论被继承多少次任然是纯虚函数
int main() {
	testStack(new arrayStack);
	testStack(new listStack);


	return 0;
}

虚析构函数

存在非正常赋值的时候,子类对象初始化父类指针

#include<iostream>
using namespace std;
class parent {
public:
	//~parent() {//new的是子类对象,但是没有调用子类析构,内存泄漏
	//	cout << "父类析构函数" << endl;

	//}
	virtual ~parent() {
		cout << "父类析构函数" << endl;

	}
	void print(){}
protected:
};

class son :public parent {
public:

	~son() {
		cout << "子类析构函数" << endl;
}
};
	void print() {}//这里没有做数据成员动态内存申请,只是举个例子,这里其实不需要虚构释放
int main() {
	//在用子类对象初始化父类指针,父类需要用虚构函数做内存释放
	parent* p = new son;
	p->print();
	delete p;

	return 0;
}

两个关键字final和override

#include<iostream>
using namespace std;
class A {
public:
	//final一定是用在虚函数中的,final子类不能存在同名函数,禁止重写
	virtual void print() final {
		cout << "重写虚函数才有的" << endl;
	}
	virtual void printData(){}
};
class B :public A {
public:
	/*void print() {
		限制子类不能写这个函数,子类只能用不能重写
	}*/
	void printData() override {//标识作用,用来检查父类父类中是否存在当前虚函数
		cout << "表示当前函数是重写函数" << endl;
	}
};

int main() {
	B b;
	A a;
	a.print();
	b.print();
	return 0;

}

C++强制类型转换

专人做专事

const_cast

#include<iostream>
using namespace std;
/*
	写法
	const_cast<要转换的类型>(要转换的目标)
	1.去掉const属性(提供一个可以修改的接口去修改const属性)
	2.加上const属性(用的较少) 
*/
class A {
public:
	A(const char* str) :str(const_cast<char*>(str)) {
		//this->str=const_cast<char*>(str);
	}
	void print() {
		cout << str << endl;
	}
protected:

	char* str;

};
class B {
public:
	B(int num):num(num){}
	void print() {
		cout << num << endl;
	}
protected:
	int num;
};
int main() {
	const int num = 11;
	//int* pNum = &num;
	//const int* pNum = &num;
	//1.作用普通指针
	int* pNum = const_cast<int*>(&num);
	*pNum = 22;
	cout << num << endl;//值没有改变
	//2.操作char* 类型指针
	A a("Iloveyou");
	a.print();
	char str[] = "Ilove you";
	A b(str);
	
	//3.操作类指针
	const B* pB = new B(0);
	//pB->print();错误,常对象要调用常成员函数
	B* ppB =const_cast<B*> (pB);
	//4.操作常量引用
	int num;
	const int& pnum = num;
	int& ppnum = const_cast<int&>(pnum);
	//5.加上const属性
	int c = 100;
	int* pc = &c;
	const int* ppc = const_cast<const int*>(pc);
	return 0;

}

static_cast

#include<iostream>
using namespace std;
/*
	static_cast<要转化的类型>(要转换的目标)
		1.基本数据类型转换(类似c语言强制类型转换)
		2.把空指针转换为目标类型指针
		3.把任何类型的变量转换为void类型
		4.用在类上面的转换(基类和派生类对象之间的转换)
		4.1进行上行转换(从子到父 指针或者引用的转换)安全
		4.2进行下行转换(从父到子 指针或者引用的转换)不安全
		注意:不能转换const
	*/
class Parent {
public:
	virtual void print() {
		cout << "parent" << endl;
	}
};
class Son :public Parent {
public:
	virtual void print() {
		cout<<"son" << endl;
	}
	void printData() {
		cout << "子类独有" << endl;
	}
	void printParent() {
		cout << "父类独有" << endl;
	}
};
int main() {
	//1.基本数据类型转换(类似c语言强制类型转换)
	char cNum = 'A';
	int iNum = static_cast<int>(cNum);
	cout << iNum << endl;
	//2.把空指针转换为目标类型指针
	double* pD = new double;
	void* pVoid = static_cast<void*>(pD);
	//3.const类型转换
	int x = 10;
	const int constNum = static_cast<const int>(x);
	//4.错误用法
	const int xx = 0;
	//int* p = static_cast<int*>(&xx);
	//从子到父
	Parent* pParent = new Son;
	pParent->print();
	Son* pSon = new Son;
	pParent = static_cast<Parent*>(pSon);
	
	Parent pp;
	Son ss;
	//ss = pp;//不安全
	//son=static_cast<Son>(parent);也不行
	Parent* ppp = new Parent;
	Son* sss = static_cast<Son*>(ppp);
	sss->print();
	sss->printData();
	sss->printParent();
	return 0;
}

dynamic_cast

#include<iostream>
using namespace std;
//多态的时候使用,上行转换和static_cast一样,下行转换,交叉转换(多继承,通过父类作为一个桥梁)
//dynamic_cast<要转换的类型>(要转换的目标)

class MM {
public:
	MM(string mmName = "父类") :mmName(mmName) {

	}
	virtual void print() {
		cout << mmName << endl;
	}

	string mmName;
};
class Girl :public MM {
public:
	Girl(string girlName = "子类") :girlName(girlName) {}
	void print() { cout << girlName << endl; }
	void printData() { cout << girlName << endl; }

	string girlName;
};
class A {
public:
	virtual void print() {
		cout << "A" << endl;
	}
protected:
};
class B {
public:
	virtual void print() {
		cout << "B" << endl;
	}
};
class C :public A, public B {
public:
	void print() {
		cout << "C";
	}
};
int main() {
	MM* pM = new MM;
	Girl* pG = new Girl;
	//上行转换
	MM* pSM = static_cast<MM*>(pG);
	MM* pDM = dynamic_cast<MM*>(pG);
	pSM->print();
	pDM->print();
	//下行转换
	Girl* pSG = static_cast<Girl*>(pM);
	Girl* pDG = dynamic_cast<Girl*>(pM);//判断是否存在多态,检查父类是否有virtual
	pSG->print();//不存在virtual不会报错,但是会中断。
	//pSG->printData();	下行转换,调用子类中父类没有函数会报错
	if (pDG != nullptr) {//因为没有转换成功所以返回空
		pDG->print();
	}
	//交叉转换
	A* a = new C;
	B* b = dynamic_cast<B*> (a);
	b->print();
	return 0;
}

reinterpret_cast

#include<iostream>
using namespace std;

int Max(int a, int b) {
	return a > b ? a : b;
}

int main() {

	int num = reinterpret_cast<int>(Max);
	cout << num << endl;//7082299
	cout << Max << endl;
	
	auto pMax = reinterpret_cast<int(*) (int, int)>(num);
	cout << pMax(1, 2) << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值