溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

發(fā)布時(shí)間:2022-03-01 09:22:10 來源:億速云 閱讀:101 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析”吧!

多態(tài)的概念

多態(tài): 從字面意思來看,就是事物的多種形態(tài)。用C++的語(yǔ)言說就是不同的對(duì)象去完成同一個(gè)行為會(huì)產(chǎn)生不同的效果。

虛函數(shù)

虛函數(shù): 被virtual關(guān)鍵字修飾的類成員函數(shù)叫做虛函數(shù)。

實(shí)例演示: 看一下代碼,其中BuyTicket成員函數(shù)被virtual關(guān)鍵字修飾

class Person
{
public:
	// 虛函數(shù)
	virtual void BuyTicket()
	{
		cout << "買票全價(jià)" << endl;
	}
};

多態(tài)構(gòu)成的條件

多態(tài)是在不同繼承關(guān)系的類對(duì)象,去調(diào)用同一函數(shù),產(chǎn)生了不同的行為。

繼承中構(gòu)成多態(tài)有兩個(gè)條件:

  • 必須有基類的指針或引用調(diào)用

  • 被調(diào)用的函數(shù)必須是虛函數(shù),其派生類必須對(duì)基類的虛函數(shù)進(jìn)行重寫

虛函數(shù)的重寫是什么?

虛函數(shù)的重寫(覆蓋): 派生類中有一個(gè)跟基類完全相同的虛函數(shù)(即派生類虛函數(shù)與基類虛函數(shù)的返回值類型、函數(shù)名字、參數(shù)列表完全相同),稱子類的虛函數(shù)重寫了基類的虛函數(shù)。(重寫是對(duì)函數(shù)體進(jìn)行重寫)

實(shí)例演示:

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "買票全價(jià)" << endl;
	}
};

class Student : public Person
{
public:
	virtual void BuyTicket() // 這里也可以不寫virtual,因?yàn)榛惖奶摵瘮?shù)屬性已經(jīng)被保留下來了,這里只是完成虛函數(shù)的重寫
	{
		cout << "買票半價(jià)" << endl;
	}
};

虛函數(shù)重寫的兩個(gè)例外:

1.協(xié)變:基類和派生類的虛函數(shù)的返回類型不同

派生類重寫基類虛函數(shù)時(shí),與基類虛函數(shù)返回值類型不同。即基類虛函數(shù)返回基類對(duì)象的指針或者引用,派生類虛函數(shù)返回派生類對(duì)象的指針或者引用時(shí),稱為協(xié)變。(也就是基類虛函數(shù)的返回類型和派生類的虛函數(shù)的返回類型是父子類型的指針或引用)

// 協(xié)變  返回值類型不同,但它們之間是父子或父父關(guān)系  返回類型是指針或者引用
// 基類虛函數(shù)   返回類型  是  基類的指針或者引用  
// 派生類虛函數(shù) 返回類型  是  基類或派生類的返回類型是基類的指針或引用

class A {};
class B : public A {};
class Person {
public:
	virtual A* f() { return new A; }
};
class Student : public Person {
public:
	virtual A* f() { return new B; }
};

2.析構(gòu)函數(shù)的重寫 基類與派生類的析構(gòu)函數(shù)的函數(shù)名不同
我在上一篇博客中說到過,基類和派生類的析構(gòu)函數(shù)的函數(shù)名會(huì)被編譯器統(tǒng)一處理成destructor,所以只要基類的析構(gòu)函數(shù)加了關(guān)鍵字virtual,就會(huì)和派生類的析構(gòu)函數(shù)構(gòu)成重寫。

我們?cè)倩氐蕉鄳B(tài)構(gòu)成的兩個(gè)條件中,完成基類虛函數(shù)的重寫我已經(jīng)介紹了,還有一個(gè)必須由基類的指針或引用調(diào)用的條件,這個(gè)應(yīng)該很好理解吧。下面舉個(gè)例子:     實(shí)例演示:

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "買票全價(jià)" << endl;
	}
};

class Student : public Person
{
public:
	virtual void BuyTicket() // 這里也可以不寫virtual,因?yàn)榛惖奶摵瘮?shù)屬性已經(jīng)被保留下來了,這里只是完成虛函數(shù)的重寫
	{
		cout << "買票半價(jià)" << endl;
	}
};

void Func1(Person& p) { p.BuyTicket(); }
void Func2(Person* p) { p->BuyTicket(); }
void Func3(Person p) { p.BuyTicket(); }

int main()
{
	Person p;
	Student s;

	// 滿足多態(tài)的條件:與類型無(wú)關(guān),父類指針指向的是誰(shuí)就調(diào)用誰(shuí)的成員函數(shù)
	// 不滿足多態(tài)的條件:與類型有關(guān),類型是誰(shuí)就調(diào)用誰(shuí)的成員函數(shù)
	cout << "基類的引用調(diào)用:" << endl;
	Func1(p);
	Func1(s);

	cout << "基類的指針調(diào)用:" << endl;
	Func2(&p);
	Func2(&s);

	cout << "基類的對(duì)象調(diào)用:" << endl;
	Func3(p);
	Func3(s);

	return 0;
}

代碼運(yùn)行結(jié)果:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

總結(jié):

  • 滿足多態(tài)的條件:成員函數(shù)調(diào)用與對(duì)象類型無(wú)關(guān),指向那個(gè)對(duì)象就調(diào)用哪個(gè)的虛函數(shù)

  • 不滿足多態(tài)的條件:成員函數(shù)的調(diào)用與對(duì)象類型有關(guān),是哪個(gè)對(duì)象類型就調(diào)用哪個(gè)對(duì)象的虛函數(shù)。

思考: 析構(gòu)函數(shù)是否要加virtual?     答案是需要的。先給大家看一個(gè)例子:

class Person
{
public:
	/*virtual*/ ~Person()
	{
		cout << "~Person()" << endl;
	}
};
class Student: public Person
{
public:
	~Student()
	{
		cout << "~Student()" << endl;
	}
};
int main()
{
	Person* p = new Person;
	Person* ps = new Student;// 不加virtual,不構(gòu)成多態(tài),父類指針只會(huì)根據(jù)類型去調(diào)用對(duì)于的析構(gòu)函數(shù)
	// 加了virtual,構(gòu)成多態(tài),父類指針會(huì)根據(jù)指向的對(duì)象去調(diào)用他的析構(gòu)函數(shù)

	delete p;
	delete ps;

	return 0;
}

下面分別是基類析構(gòu)函數(shù)不加virtual和加virtual的代碼運(yùn)行結(jié)果:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

可以看出,不加virtual關(guān)鍵字時(shí),第二個(gè)對(duì)象delete時(shí)沒有調(diào)用子類的析構(gòu)函數(shù)清理釋放空間。為什么呢?因?yàn)椴患觱irtual關(guān)鍵字時(shí),兩個(gè)析構(gòu)函數(shù)不構(gòu)成多態(tài),所以調(diào)用析構(gòu)函數(shù)時(shí)是與類型有關(guān)的,因?yàn)槎际嵌际歉割愵愋?,所以只?huì)調(diào)用父類的析構(gòu)函數(shù)。加了virtual關(guān)鍵字時(shí),因?yàn)閮蓚€(gè)析構(gòu)函數(shù)被編譯器處理成同名函數(shù)了,所以完成了虛函數(shù)的重寫,且是父類指針調(diào)用,所以此時(shí)兩個(gè)析構(gòu)函數(shù)構(gòu)成多態(tài),所以調(diào)用析構(gòu)函數(shù)時(shí)是與類型無(wú)關(guān)的,因?yàn)楦割愔羔樦赶虻氖亲宇悓?duì)象,所以會(huì)調(diào)用子類的析構(gòu)函數(shù),子類調(diào)用完自己的析構(gòu)函數(shù)又會(huì)自動(dòng)調(diào)用父類的析構(gòu)函數(shù)來完成對(duì)父類資源的清理。     所以總的來看,基類的析構(gòu)函數(shù)是要加virtual的。

C++11override和final

final: 修飾虛函數(shù),表示該虛函數(shù)不可以被重寫(還可以修飾類,表示該類不可以被繼承)

實(shí)例演示:

class Car
{
public:
	// final  表示該虛函數(shù)不能被重寫  也可以修飾類,表示該類不可以被繼承
	virtual void Drive() final {}
};
class Benz :public Car
{
public:
	virtual void Drive() { cout << "Benz-舒適" << endl; }
};

編譯器檢查結(jié)果: 由于dirve字母編寫錯(cuò)誤,所以編譯器檢查出沒有重寫基類的虛函數(shù)

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

2.overide: 檢查派生類虛函數(shù)是否重寫了基類的某個(gè)虛函數(shù)         實(shí)例演示:

class Car
{
public:
	// final  表示該虛函數(shù)不能被重寫  也可以修飾類,表示該類不可以被繼承
	virtual void Drive() final {}
};
class Benz :public Car
{
public:
	virtual void Drive() { cout << "Benz-舒適" << endl; }
};

編譯器檢查結(jié)果:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

重載、重寫和重定義(隱藏)

名稱作用域函數(shù)名其他
重載兩個(gè)函數(shù)在同一作用域相同參數(shù)類型不同
重寫兩個(gè)函數(shù)分別再基類和派生類的作用域相同函數(shù)返回類型和參數(shù)類型一樣
重定義(隱藏)兩個(gè)函數(shù)分別再基類和派生類的作用域相同兩個(gè)基類和派生類的同名函數(shù)不是構(gòu)成重寫就是重定義

抽象類

概念: 在虛函數(shù)的后面寫上 =0 ,則這個(gè)函數(shù)為純虛函數(shù)。包含純虛函數(shù)的類叫做抽象類(也叫接口類),抽象類不能實(shí)例化出對(duì)象。派生類繼承后也不能實(shí)例化出對(duì)象,只有重寫純虛函數(shù),派生類才能實(shí)例化象純虛函數(shù)規(guī)范了派生類必須重寫,另外純虛函數(shù)更體現(xiàn)出了接口繼承。

總結(jié)出幾個(gè)特點(diǎn):

  • 虛函數(shù)后面加上=0

  • 不能實(shí)例化出對(duì)象

  • 派生類如果不重寫基類的純虛函數(shù)那么它也是抽象類,不能實(shí)例化出對(duì)象

  • 抽象類嚴(yán)格限制派生類必須重寫基類的純虛函數(shù)

  • 體現(xiàn)了接口繼承

實(shí)例演示:

class Car
{
public:
	virtual void Drive() = 0;
};
class Benz : public Car
{
public:
	virtual void Drive()
	{
		cout << "Benz" << endl;
	}
};


class BMW : public Car
{
public:
	virtual void Drive () override
	{
		cout << "BMW" << endl;
	}
};

int main()
{
	Car* pBenZ = new Benz;
	pBenZ->Drive();

	Car* pBMW = new BMW;
	pBMW->Drive();

	delete pBenZ;
	delete pBMW;
	return 0;
}

代碼運(yùn)行結(jié)果:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

抽象類的意義?

  • 強(qiáng)制子類完成父類虛函數(shù)的重寫

  • 表示該類是抽象類,沒有實(shí)體(例如:花、車和人等)

接口繼承和實(shí)現(xiàn)繼承

普通函數(shù)的繼承是一種實(shí)現(xiàn)繼承,派生類繼承了基類函數(shù),可以使用函數(shù),繼承的是函數(shù)的實(shí)現(xiàn)。虛函數(shù)的繼承是一種接口繼承,派生類繼承的是基類虛函數(shù)的接口,目的是為了重寫,達(dá)成多態(tài),繼承的是接口。所以如果不實(shí)現(xiàn)多態(tài),不要把函數(shù)定義成虛函數(shù)。

多態(tài)的原理

虛函數(shù)表

概念: 一個(gè)含有虛函數(shù)的類中至少有一個(gè)虛函數(shù)指針,這個(gè)指針指向了一張表——虛函數(shù)表(簡(jiǎn)稱虛表),這張表中存放了這個(gè)類中所有的虛函數(shù)的地址。

計(jì)算一下下面這個(gè)類的大?。?/p>

class Base
{
public:
	virtual void func1() {}
	virtual void func2() {}
public:
	int _a;
};
int main()
{
	cout << sizeof(Base) << endl;
	return 0;
}

代碼運(yùn)行結(jié)果如下:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

這個(gè)類中存放了一個(gè)虛表指針和一個(gè)成員變量,所以總大小就是8。給大家看一下它的類對(duì)象模型:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

實(shí)例演示:

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "買票全價(jià)" << endl;
	}
	virtual void func()
	{
		cout << "func()" << endl;
	}
	int _p = 1;
};

class Student : public Person
{
public:
	virtual void BuyTicket() // 這里也可以不寫virtual,因?yàn)榛惖奶摵瘮?shù)屬性已經(jīng)被保留下來了,這里只是完成虛函數(shù)的重寫
	{
		cout << "買票半價(jià)" << endl;
	}
	int _s = 1;
};

int main()
{
	Person p;
	Student s;

	return 0;
}

類對(duì)象模型如下:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

可以看出,兩個(gè)虛函數(shù)地址是不一樣的,其實(shí)子類會(huì)先把父類的虛表拷貝一份下來,如果子類重寫了虛函數(shù),那么子類的虛函數(shù)的地址將會(huì)覆蓋虛表中的地址,如果沒有重寫,那么將不覆蓋。

總結(jié)幾點(diǎn):

  • 子類對(duì)象由兩部分構(gòu)成,一部分是父類繼承下來的成員,虛表指針指向的虛表有父類的虛函數(shù),也有子類新增的虛函數(shù)

  • 子類完成父類虛函數(shù)的重寫其實(shí)是對(duì)繼承下來的虛表的中重寫了的虛函數(shù)進(jìn)行覆蓋,把地址更換了,語(yǔ)法層是稱為覆蓋

  • 虛函數(shù)表本質(zhì)是一個(gè)存虛函數(shù)指針的指針數(shù)組,一般情況這個(gè)數(shù)組最后面放了一個(gè)nullptr

  • 虛表生成的過程:先將基類中的虛表內(nèi)容拷貝一份到派生類虛表中 b.如果派生類重寫了基類中某個(gè)虛函數(shù),用派生類自己的虛函數(shù)覆蓋虛表中基類的虛函數(shù) c.派生類自己新增加的虛函數(shù)按其在派生類中的聲明次序增加到派生類虛表的最后

下面我們來討論一下虛表存放的位置和虛表指針存放的位置

虛表指針肯定是存在類中的,從上面的類對(duì)象模型中可以看出。其次虛表存放的是虛函數(shù)的地址,這些虛函數(shù)和普通函數(shù)一樣,都會(huì)被編譯器編譯成指令,然后放進(jìn)代碼段。虛表也是存在代碼段的,因?yàn)橥愋偷膶?duì)象共用一張?zhí)摫?。下面帶大家?yàn)證一下(環(huán)境:vs2019)

驗(yàn)證代碼:

class Base
{
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
	virtual void func3() { cout << "Base::func3" << endl; }
	void func() {}

	int b = 0;
};

class Derive :public Base
{
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func2() { cout << "Derive::func2" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	virtual void func5() { cout << "Derive::func5" << endl; }

	int d = 0;
};

void func() {}
int globalVar = 10;
int main()
{
	Base b;
	Derive d;
	const char* pChar = "hello";
	int c = 1;
	static int s = 20;
	int* p = new int;
	const int i = 10;

	printf("棧變量:%p\n", &c);
	printf("虛表指針:%p\n", (int*)&b);
	printf("對(duì)象成員:%p\n", ((int*)&b + 1));
	printf("堆變量:%p\n", p);
	printf("代碼段常量:%p\n", pChar);
	printf("普通函數(shù)地址:%p\n", func);
	printf("成員函數(shù)地址:%p\n", &Base::func);
	printf("虛函數(shù):%p\n", &Base::func1);
	printf("虛函數(shù)表:%p\n", *(int*)&b);
	printf("數(shù)據(jù)段:%p\n", &s);
	printf("數(shù)據(jù)段:%p\n", &globalVar);

	delete p;
	return 0;
}

代碼運(yùn)行結(jié)果如下:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

容易看出,代碼段常量存放的地址和虛表存放的地址很接近,和數(shù)據(jù)段的地址也很接近,所以可以猜測(cè)虛表存放在數(shù)據(jù)段或代碼段,更可能是在代碼段。

原理

多態(tài)是在運(yùn)行時(shí)到指向的對(duì)象中的虛表中查找要調(diào)用的虛函數(shù)的地址,然后進(jìn)行調(diào)用。

總結(jié):

  • 多態(tài)滿足的兩個(gè)條件:一個(gè)是虛函數(shù)的覆蓋,一個(gè)是對(duì)象的指針和引用調(diào)用

  • 滿足多態(tài)后,函數(shù)的調(diào)用不是編譯時(shí)確認(rèn)的,而是在運(yùn)行時(shí)確認(rèn)的。

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

動(dòng)態(tài)綁定和靜態(tài)綁定

  • 靜態(tài)綁定: 發(fā)生在編譯時(shí),也就是早期綁定,就是我們之前說過的函數(shù)重載就是屬于靜態(tài)綁定,也稱靜態(tài)多態(tài)。

  • 動(dòng)圖綁定: 發(fā)生在運(yùn)行時(shí),也就是后期綁定,多態(tài)就是發(fā)生在運(yùn)行時(shí),也稱動(dòng)態(tài)多態(tài)。

單繼承和多繼承的虛表

單繼承的虛表

先看下面的代碼(單繼承)

class Base
{
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
	virtual void func3() { cout << "Base::func3" << endl; }
	void func() {}

	int b = 0;
};

class Derive :public Base
{
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func2() { cout << "Derive::func2" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	virtual void func5() { cout << "Derive::func5" << endl; }

	int d = 0;
};

觀察它的類對(duì)象模型:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

在上面的類對(duì)象模型中,派生類中只可以看見func1和func2,后面兩個(gè)函數(shù)看不見,這是因?yàn)榫幾g器把這兩個(gè)新增的虛函數(shù)給隱藏了,為了我們能夠更好的觀察,我們可以通過寫代碼來看。         先定義一個(gè)函數(shù)指針:

typedef void(*VF_PTR)(); // 給函數(shù)指針typedef

下面是打印虛表的代碼:

void PrintVFTable(VF_PTR* pTable)
{
	for (size_t i = 0; pTable[i] != nullptr; ++i)
	{
		printf("vfTable[%d]:%p->", i, pTable[i]);
		VF_PTR f = pTable[i];
		f();// 通過函數(shù)地址調(diào)用函數(shù)
	}

	cout << endl;
}

下面我們只需要通過傳虛表地址的方式來調(diào)用函數(shù)打印虛表,虛表地址如何獲取呢?從上面的類對(duì)象模型可以知道,類對(duì)象的前四個(gè)地址存放的是虛表指針,虛表指針也就是虛表的指針,所以我們要獲取類對(duì)象的前四個(gè)字節(jié)。下面是獲取方法:

(VF_PTR*)*(int*)&b;

先將類對(duì)象的地址取出,然后強(qiáng)轉(zhuǎn)為整形,解引用就會(huì)按照四個(gè)字節(jié)來獲取內(nèi)容,這四個(gè)字節(jié)的內(nèi)容是虛表指針,其實(shí)也是虛表的地址,我們可以把這個(gè)整形強(qiáng)轉(zhuǎn)為函數(shù)地址的類型就可以了。

打印虛表:

int main()
{
	Base b;
	Derive d;

	PrintVFTable((VF_PTR*)*(int*)&b);
	PrintVFTable((VF_PTR*)*(int*)&d);

	return 0;
}

打印結(jié)果如下:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

可以看出派生類對(duì)象中新增的虛函數(shù)會(huì)按照虛函數(shù)函數(shù)次序聲明放在虛表的最后。

多繼承的虛函數(shù)表

看下面代碼(多繼承)

class Base1 
{
public:
	virtual void func1() { cout << "Base1::func1" << endl; }
	virtual void func2() { cout << "Base1::func2" << endl; }
private:
	int b1;
};
class Base2 
{
public:
	virtual void func1() { cout << "Base2::func1" << endl; }
	virtual void func2() { cout << "Base2::func2" << endl; }
private:
	int b2 = 1;
};
class Derive : public Base1 , public Base2 
{
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
private:
	int d1 = 1;
};

類對(duì)象模型如下:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

為了更好地觀察,我們還是通過打印虛表來觀察:

int main()
{
	Derive d;
	cout << sizeof(Derive) << endl;
	cout << "Base1的虛表:" << endl;
	PrintVFTable((VF_PTR*)*(int*)&d);

	cout << "Base2的虛表:" << endl;
	PrintVFTable((VF_PTR*)*(int*)((char*)&d+sizeof(Base1)));

	cout << "Derive的成員變量d:" << endl;
	//PrintVFTable((VF_PTR*)*(int*)((char*)&d + sizeof(Base1) + sizeof(Base2)));
	cout << *(int*)((char*)&d + sizeof(Base1) + sizeof(Base2)) << endl;
	return 0;
}

打印結(jié)果如下:

C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析

可以看出,派生類新增的虛函數(shù)放在了第一個(gè)繼承的對(duì)象的虛表中最后了。

感謝各位的閱讀,以上就是“C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)C++多態(tài)的實(shí)現(xiàn)與原理及抽象類實(shí)例分析這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI