做電影網(wǎng)站教程網(wǎng)站建設(shè)網(wǎng)站設(shè)計(jì)
面試題29:什么是嵌套類(lèi),它有什么作用
嵌套類(lèi)指的是在一個(gè)類(lèi)的內(nèi)部定義的另一個(gè)類(lèi)。嵌套類(lèi)可以作為外部類(lèi)的一個(gè)成員,但它與其聲明類(lèi)型緊密關(guān)聯(lián),不應(yīng)被用作通用類(lèi)型。嵌套類(lèi)可以訪(fǎng)問(wèn)外部類(lèi)的所有成員,包括私有成員,這是嵌套類(lèi)的一個(gè)重要特性。
嵌套類(lèi)的作用主要有以下幾點(diǎn):
(1)封裝和隱藏實(shí)現(xiàn)細(xì)節(jié):嵌套類(lèi)可以用于隱藏實(shí)現(xiàn)細(xì)節(jié),使得外部類(lèi)看起來(lái)更加簡(jiǎn)潔和易于使用。
(2)提供服務(wù):嵌套類(lèi)通常是為外部類(lèi)提供服務(wù)的,它可以訪(fǎng)問(wèn)外部類(lèi)的所有成員,因此可以方便地實(shí)現(xiàn)與外部類(lèi)相關(guān)的功能。
(3)代碼組織:嵌套類(lèi)可以用于組織代碼,將相關(guān)的類(lèi)放在一起,提高代碼的可讀性和可維護(hù)性。
需要注意的是,嵌套類(lèi)不應(yīng)被公開(kāi)可見(jiàn),除非必要。在設(shè)計(jì)良好的庫(kù)中,開(kāi)發(fā)人員幾乎不需要使用嵌套類(lèi)來(lái)實(shí)例化對(duì)象或聲明變量。在大多數(shù)情況下,嵌套類(lèi)應(yīng)該被視為實(shí)現(xiàn)細(xì)節(jié)的一部分,而不是公開(kāi)的 API 。
嵌套類(lèi)訪(fǎng)問(wèn)權(quán)限遵循一般的類(lèi)成員訪(fǎng)問(wèn)權(quán)限規(guī)則,嵌套類(lèi)可以是 public 、 protected 或 private ,這取決于它們?cè)谕獠款?lèi)中的聲明方式。這些訪(fǎng)問(wèn)修飾符決定了嵌套類(lèi)在外部類(lèi)的外部可見(jiàn)性和可訪(fǎng)問(wèn)性。
(1) public 嵌套類(lèi)
如果嵌套類(lèi)被聲明為 public ,則它在外部類(lèi)的外部是可見(jiàn)的,并且可以被任何能夠訪(fǎng)問(wèn)外部類(lèi)的代碼所訪(fǎng)問(wèn)和使用。
(2) protected 嵌套類(lèi)
如果嵌套類(lèi)被聲明為 protected ,則它在外部類(lèi)的外部是不可見(jiàn)的,但可以被外部類(lèi)的派生類(lèi)訪(fǎng)問(wèn)。注意:一般很少將嵌套類(lèi)定義成 protected 。
(3)Private嵌套類(lèi)
如果嵌套類(lèi)被聲明為 private ,則它在外部類(lèi)的外部是不可見(jiàn)的,并且只能被外部類(lèi)的成員函數(shù)訪(fǎng)問(wèn)。
嵌套類(lèi)在實(shí)現(xiàn)某些設(shè)計(jì)模式(如工廠模式、組合模式等)時(shí)也非常有用,典型的比如使用嵌套類(lèi)實(shí)現(xiàn)工廠模式:
#include <iostream>
#include <string> using namespace std;// 外部類(lèi),作為工廠類(lèi)的容器
class AnimalFactory
{
public:// 嵌套類(lèi),定義不同的動(dòng)物 class Animal{public:virtual void eat() {}};// 嵌套類(lèi),實(shí)現(xiàn)具體的動(dòng)物類(lèi)(貓)class Cat : public Animal{public:void eat() {printf("cat eat\n");}};// 嵌套類(lèi),實(shí)現(xiàn)具體的動(dòng)物類(lèi)(狗)class Dog : public Animal{public:void eat(){printf("dog eat\n");}};// 工廠方法,根據(jù)傳入的字符串創(chuàng)建相應(yīng)的動(dòng)物 static std::shared_ptr<Animal> createAnimal(const std::string& animalType) {if ("Cat" == animalType) {return std::shared_ptr<Animal>(new Cat);}else if ("Dog" == animalType){return std::shared_ptr<Animal>(new Dog);}return nullptr; // 如果類(lèi)型不匹配,返回空指針 }
};int main()
{std::shared_ptr<AnimalFactory::Animal> cat = AnimalFactory::createAnimal("Cat");cat->eat();std::shared_ptr<AnimalFactory::Animal> dog = AnimalFactory::createAnimal("Dog");dog->eat();return 0;
}
上面代碼的輸出為:
cat eat
dog eat
在這個(gè)例子中,AnimalFactory 類(lèi)包含了 3 嵌套類(lèi) Animal 、Cat 和 Dog,Cat 類(lèi)和 Dog 類(lèi)分別實(shí)現(xiàn)了 Animal 基類(lèi)的 eat 方法。AnimalFactory 類(lèi)還提供了一個(gè)靜態(tài)工廠方法 createAnimal,該方法根據(jù)傳入的字符串參數(shù)創(chuàng)建并返回相應(yīng)類(lèi)型的動(dòng)物對(duì)象。main 函數(shù)中展示了如何使用工廠方法來(lái)創(chuàng)建和使用不同的對(duì)象。
使用嵌套類(lèi)實(shí)現(xiàn)工廠模式的好處是,所有與形狀相關(guān)的類(lèi)都集中在 AnimalFactory 類(lèi)中,這有助于保持代碼的整潔和組織性。此外,通過(guò)將工廠方法放在 AnimalFactory 類(lèi)中,可以確保只有這個(gè)類(lèi)能夠創(chuàng)建形狀對(duì)象,這有助于控制對(duì)象的創(chuàng)建過(guò)程。
面試題30:什么是類(lèi)靜態(tài)成員,它有什么作用
類(lèi)靜態(tài)成員是類(lèi)中聲明為 static 的成員,包括靜態(tài)成員變量和靜態(tài)成員函數(shù)。靜態(tài)數(shù)據(jù)成員是與類(lèi)關(guān)聯(lián)的全局變量,而不是與類(lèi)的實(shí)例關(guān)聯(lián)。靜態(tài)成員函數(shù)可以在沒(méi)有類(lèi)實(shí)例的情況下調(diào)用,且只能訪(fǎng)問(wèn)靜態(tài)成員變量或其他靜態(tài)成員函數(shù)。
如下為類(lèi)靜態(tài)成員的樣例:
#include <iostream> class MyClass
{
public:MyClass() {}~MyClass() {}public:static void printStaticVal(){printf("static value = %d\n", m_staticVal);}static void setStaticVal(int val){m_staticVal = val;}private:static int m_staticVal;
};int MyClass::m_staticVal = 0;int main()
{MyClass::setStaticVal(1);MyClass::printStaticVal();return 0;
}
上面代碼的輸出為:
static value = 1
上面代碼中, MyClass 有一個(gè)靜態(tài)成員變量 m_staticVal 和兩個(gè)靜態(tài)成員函數(shù) printStaticVal 和 setStaticVal 。這些靜態(tài)成員可以被類(lèi)的任何對(duì)象訪(fǎng)問(wèn),也可以直接通過(guò)類(lèi)名訪(fǎng)問(wèn)。當(dāng)通過(guò) MyClass::setStaticVal 設(shè)置 m_staticVal 的值時(shí),所有 m_staticVal 的對(duì)象都會(huì)看到相同的值,因?yàn)殪o態(tài)成員是共享的。
類(lèi)靜態(tài)成員有如下 5 個(gè)特點(diǎn):
(1)存儲(chǔ):靜態(tài)數(shù)據(jù)成員在內(nèi)存中只有一份拷貝,無(wú)論創(chuàng)建多少個(gè)類(lèi)的對(duì)象。
(2)初始化:靜態(tài)數(shù)據(jù)成員在類(lèi)外部進(jìn)行初始化,且只初始化一次。
(3)訪(fǎng)問(wèn):靜態(tài)成員函數(shù)只能訪(fǎng)問(wèn)靜態(tài)數(shù)據(jù)成員或其他靜態(tài)成員函數(shù),不能訪(fǎng)問(wèn)非靜態(tài)成員。
(4)生命周期:靜態(tài)成員的生命周期與程序的生命周期相同。
(5)共享:所有類(lèi)的實(shí)例共享同一個(gè)靜態(tài)數(shù)據(jù)成員。
類(lèi)靜態(tài)成員的主要作用是提供類(lèi)級(jí)別的信息或功能,這些信息或功能與類(lèi)的具體實(shí)例無(wú)關(guān)。靜態(tài)數(shù)據(jù)成員可以用于存儲(chǔ)類(lèi)級(jí)別的常量、統(tǒng)計(jì)信息或共享資源。靜態(tài)成員函數(shù)可以用于執(zhí)行不依賴(lài)于類(lèi)實(shí)例的操作,如修改靜態(tài)數(shù)據(jù)成員或執(zhí)行與類(lèi)相關(guān)的全局操作。此外,靜態(tài)成員函數(shù)還可以用于訪(fǎng)問(wèn)靜態(tài)數(shù)據(jù)成員,并在沒(méi)有類(lèi)實(shí)例的情況下被調(diào)用。
面試題31:什么是淺拷貝和深拷貝,其各自適用的場(chǎng)景是什么
淺拷貝( Shallow Copy ):只復(fù)制對(duì)象的值或?qū)ο蟮囊?#xff08;指針),但不復(fù)制對(duì)象引用的實(shí)際對(duì)象。如果對(duì)象內(nèi)部包含動(dòng)態(tài)分配的內(nèi)存或其他資源,則這些資源在淺拷貝后會(huì)被多個(gè)對(duì)象共享,可能導(dǎo)致資源釋放時(shí)的錯(cuò)誤(如雙重刪除)。淺拷貝適用于對(duì)象間共享資源且不需要修改這些資源的場(chǎng)景。淺拷貝可以提高性能,因?yàn)椴恍枰獜?fù)制大量數(shù)據(jù)。但是,如果共享的資源被意外修改或釋放,可能會(huì)導(dǎo)致問(wèn)題。
深拷貝( Deep Copy ):復(fù)制對(duì)象的值以及對(duì)象引用的實(shí)際對(duì)象。對(duì)于包含動(dòng)態(tài)分配內(nèi)存的對(duì)象,深拷貝會(huì)創(chuàng)建這些內(nèi)存區(qū)域的新副本,確保每個(gè)對(duì)象都有自己獨(dú)立的資源副本。深拷貝適用于需要對(duì)象擁有獨(dú)立資源副本的場(chǎng)景。深拷貝可以確保每個(gè)對(duì)象都可以獨(dú)立修改資源而不會(huì)影響其他對(duì)象。但是,深拷貝可能占用更多的內(nèi)存,并且在復(fù)制大量數(shù)據(jù)時(shí)可能會(huì)影響性能。
面試題32:C++中默認(rèn)的拷貝構(gòu)造函數(shù)執(zhí)行的是深拷貝還是淺拷貝
C++ 中默認(rèn)的拷貝構(gòu)造函數(shù)執(zhí)行的是淺拷貝。它只逐成員復(fù)制對(duì)象的內(nèi)容,如果成員是指針或引用,那么它只是復(fù)制這些指針或引用的值,而不是它們所指向的實(shí)際對(duì)象。
面試題33:如何在C++中實(shí)現(xiàn)深拷貝
要實(shí)現(xiàn)深拷貝,需要自定義拷貝構(gòu)造函數(shù)與重載賦值運(yùn)算符,并在其中為動(dòng)態(tài)分配的內(nèi)存或其他資源創(chuàng)建新的副本。如下為樣例代碼:
#include <iostream> class MyClass
{
public:MyClass(int value) {m_val = new int(value);}~MyClass() {delete m_val;}// 拷貝構(gòu)造函數(shù)(深拷貝) MyClass(const MyClass& other){m_val = new int(*(other.m_val));}// 賦值運(yùn)算符(深拷貝) MyClass& operator=(const MyClass& other){if (this != &other) {delete m_val; // 先刪除當(dāng)前對(duì)象的數(shù)據(jù) m_val = new int(*(other.m_val)); // 然后復(fù)制其他對(duì)象的數(shù)據(jù) }return *this;}public:void setVal(int val){*m_val = val;}void printVal(){printf("val = %d\n",*m_val);}private:int* m_val;
};int main() {MyClass obj1(0);MyClass obj2 = obj1;obj2.setVal(1); // 通過(guò) obj2 對(duì)象修改值,obj1 不會(huì)被改變printf("obj1: ");obj1.printVal();printf("obj2: ");obj2.printVal();return 0;
}
上面代碼的輸出為:
obj1: val = 0
obj2: val = 1
在上面代碼中,拷貝構(gòu)造函數(shù)和賦值運(yùn)算符都創(chuàng)建了一個(gè)新的整數(shù),并復(fù)制了 obj1 對(duì)象中 m_val 指針指向的值。這樣,每個(gè)對(duì)象都有自己獨(dú)立的內(nèi)存塊,修改一個(gè)對(duì)象不會(huì)影響另一個(gè)對(duì)象。
深拷貝通常比淺拷貝更耗時(shí)和資源密集,因?yàn)樗婕暗椒峙漕~外的內(nèi)存和復(fù)制數(shù)據(jù)。然而,深拷貝提供了更好的數(shù)據(jù)完整性和安全性,特別是在涉及到多個(gè)對(duì)象共享同一份數(shù)據(jù)時(shí)。