日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++虛函數和多態超詳細分析_C 語言

作者:king&南星 ? 更新時間: 2023-03-18 編程語言

1.什么是虛函數

C++類中用virtual修飾的函數叫做虛函數,構造函數沒有虛構造函數,存在虛析構函數,C++所有虛函數都是一個指針去存儲的,所以具有虛函數的類,內存會增加一個指針大小的內存

#include<iostream>
#include<string>
using namespace std;
class MM
{
public:
	//虛函數指針是同一個,所以無論該類中有多少個虛函數,
	//占用的內存就只是一個指針的大小
	virtual void print()
	{
		cout << "我是第一個虛函數" << endl;
	}
	virtual void printData() 
	{
		cout << "我是第二個虛函數" << endl;
	}
protected:
};
class son:public MM
{
public:
	void print() 
	{
		//該函數也是虛函數,
        //父類中同名函數是虛函數
		//所以子類該函數也是虛函數
	}
protected:
};
int main() 
{
	cout << sizeof(MM) << endl;
	cout << "...................." << endl;
	//虛函數表的理解,下面帶圖解
	MM mm;
	long long** p = (long long**)&mm;
	using Func = void(*)();
	Func f1 = (Func)p[0][0];
	Func f2 = (Func)p[0][1];
	f1();
	f2();
	return 0;
}

2.純虛函數

純虛函數也是虛函數的一種,只是沒有函數體,下面請看怎么表示沒有函數體

純虛函數——>虛函數=0;

具有一個或者多個虛函數的類叫做抽象類

  • 抽象類不能構建對象
  • 但是可以構建函數指針
#include<iostream>
using namespace std;
class MM
{
public:
	virtual void print() = 0;
};
int main()
{
	//MM mm; //抽象類不能構建對象
	MM* pmm = nullptr;
	return 0;
}

3.c++多態

多態指的是因為指針的不同的賦值操作所導致的同一行為的不同結果。多態的這個概念東西不太重要,重要的是什么樣的情況調用什么樣的行為

  • 正常指針和正常對象調用行為,就近原則
  • 父類指針被子類對象初始化
  • 函數有virtual看對象類型
  • 函數沒有virtual看指針類型
  • final關鍵字 禁止子類重寫父類方法
  • override顯示說明當前函數是重寫函數

多態三個必要性條件:

  • 父類中存在虛函數
  • 存在不正常指針的引用(不正常賦值關系)
  • public繼承
#include<iostream>
using namespace std;
class MM
{
public:
	void print()
	{
		cout << "父類" << endl;
	}
	virtual void printData()
	{
		cout << "MM" << endl;
	}
};
class son :public MM 
{
public:
	void print() 
	{
		cout << "子類" << endl;
	}
	void printData() 
	{
		cout << "son" << endl;
	}
};
int main()
{
	MM* pmm = new son;
	pmm->print();
	pmm->printData();
	return 0;
}

4.純虛函數和ADT過程

ADT:abstract data type抽象數據類型,主要是通過繼承抽象類中,子類必須要實現父類的抽象方法,子類才可以創建對象。

#include<iostream>
#include<string>
using namespace std;
class data
{
public:
	string name;
	int age;
};
class MM
{
public:
	virtual bool empty() = 0;
	virtual int size() = 0;
};
class List:public MM
{
public:
	bool empty()
	{
		return 0;
	}
	int size()
	{
		return NULL;
	}
};
int main()
{
	MM* pmm = new List;
	pmm->empty();
	pmm->size();
}

5.虛析構函數

virtual修飾的析構函數就是虛析構函數,當存在子類對象初始化父類指針的時候,父類析構函數就要是虛析構函數,否則只會釋放父類,存在內存泄漏問題

#include<iostream>
using namespace std;
class MM
{
public:
	virtual ~MM()
	{
		cout << "父類" << endl;
	}
};
class son:public MM
{
public:
	~son()
	{
		cout << "子類" << endl;
	}
};
int main()
{
	MM* pmm = new son;
	delete pmm;
	return 0;
}

6.dynamic_cast類型轉換

  • 上行轉換 子類到父類 和staic_cast差不多
  • 下行轉換 父類到子類 dynamic_cast更為安全
  • 交叉轉換 多繼承
#include<iostream>
using namespace std;
class MM
{
public:
	virtual void print() { cout << "MM" << endl; }
};
class son:public MM
{
public:
	void print() { cout << "son" << endl; }
};
class A
{
public:
	virtual void print(){}
};
class B
{
public:
	virtual void print() {}
};
class C:public A,public B
{
public:
	void print()
	{
		cout << "c" << endl;
	}
};
int main()
{
	MM* partent = new MM;
	son* Son = new son;
	//上行轉換----->沒有必要
	MM* p = static_cast<MM*>(Son);
	MM* pp = dynamic_cast<MM*>(Son);
	MM* ppp = Son;       //可以
	//下行轉換
	son* x = dynamic_cast<son*>(partent); //安全,父類沒有virtual會報錯---->多態
	if(!x)
	{
		printf("error");
	}                           //下行轉換不安全,不會申請成功
	A* a = new A;
	B* b = dynamic_cast<B*>(a);
	b->print();
	return 0;
}

7.成員函數指針

#include<iostream>
#include<functional>
using namespace std;
class MM
{
public:
	void print() { cout << "king" << endl; }
	static void printData() { cout << "MM" << endl; }
};
int main()
{
	void(*p)() = &MM::printData;
	p();
	//必須通過對象調用
	void(MM::*pp)() = &MM::print;
	MM mm;
	(mm.*pp)();
	//函數適配器,讓函數調用形態可以適用于別的形態
	auto f = bind(&MM::print, &mm);
	f();
	return 0;
}

原文鏈接:https://blog.csdn.net/qq_72157449/article/details/128699474

欄目分類
最近更新