訪問國外網(wǎng)站 速度慢最近的新聞大事20條
重載和重寫的區(qū)別
重載是overload,覆蓋是override
重載屬于編譯時(shí)多態(tài),覆蓋屬于運(yùn)行時(shí)多態(tài)
運(yùn)行時(shí)多態(tài)和編譯時(shí)多態(tài)
運(yùn)行時(shí)多態(tài)指的是在運(yùn)行的時(shí)候才知道要調(diào)用哪一個(gè)函數(shù),編譯時(shí)多態(tài)是指在編譯的時(shí)候就知道調(diào)用哪一個(gè)函數(shù)。
運(yùn)行時(shí)多態(tài)
可以使得父類指針調(diào)用子類函數(shù),當(dāng)然子類指針也可以調(diào)用父類函數(shù)
#include <iostream>class Base {
public:virtual void show() { std::cout << "Base class" << std::endl; }
};class Derived : public Base {
public:void show() override { std::cout << "Derived class" << std::endl; }
};int main() {Base* ptr;Derived obj;ptr = &obj;ptr->show(); // 調(diào)用 Derived::show(),發(fā)生運(yùn)行時(shí)多態(tài)
}
by the way,如果代碼不慎寫為了這樣,編譯器也不會(huì)報(bào)錯(cuò),而是友善提示:
函數(shù) ‘show’ 從類 ‘Base’ 中隱藏了一個(gè)非虛擬函數(shù)
#include <iostream>class Base {
public:void show() { std::cout << "Base class" << std::endl; }
};class Derived : public Base {
public:void show() { std::cout << "Derived class" << std::endl; }
};int main() {Base* ptr;Derived obj;ptr = &obj;ptr->show(); // 調(diào)用 Derived::show(),發(fā)生運(yùn)行時(shí)多態(tài)
}
因?yàn)樵贑++ 規(guī)定,如果子類定義了與基類同名的函數(shù),則基類中的所有同名函數(shù)都會(huì)被隱藏(即使參數(shù)列表不同)。
那如果有一個(gè)需求,首先滿足Derived類繼承了Base,同時(shí)有自己的show函數(shù)(參數(shù)列表和Base不一樣,因此單純的override是不行的),可以在Derived類里添加一句using Base::show;
即可。
class Base {
public:virtual void show() { std::cout << "Base class" << std::endl; }
};class Derived : public Base {
public:using Base::show;void show(int a) { std::cout << "Derived class" <<a<< std::endl; }
};int main() {Derived* ptr; //注意這里變?yōu)榱薉erived*Derived obj;ptr = &obj;ptr->show();ptr->show(1);
}
如果有對(duì)多態(tài)學(xué)術(shù)不精,只記得在虛函數(shù)的加持下可以使得父類指針訪問子類函數(shù),而將上述代碼寫為了
Base* ptr; Derived obj;ptr = &obj;ptr->show();ptr->show(1);
代碼是不會(huì)通過檢查的,因?yàn)楦割愔羔樋梢哉{(diào)用子類的函數(shù),但前提是 這個(gè)函數(shù)必須在父類中聲明為 virtual,這樣才能實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)(動(dòng)態(tài)綁定)。
雖然我們?cè)诟割惱镉?strong>show()這個(gè)函數(shù),但show(int) 不是 Base 類的虛函數(shù),所以 Base* 看不到 Derived 里的 show(int),導(dǎo)致編譯錯(cuò)誤。
編譯時(shí)多態(tài)
特點(diǎn):
- 同一作用域內(nèi),多個(gè)函數(shù)同名但參數(shù)列表不同(參數(shù)個(gè)數(shù)或類型不同)。
- 在編譯時(shí)根據(jù)函數(shù)調(diào)用的參數(shù)選擇具體的函數(shù)(編譯器做“名字修飾(Name Mangling)”處理)。
- 不會(huì)引發(fā)運(yùn)行時(shí)開銷,函數(shù)的匹配完全在編譯階段完成。
繼承
公有繼承
class Base {
public:int a;
protected:int b;private:int c;
};class Derived : public Base {void print(){cout<<b;}
};int main() {Derived* ptr;Derived obj;ptr = &obj;cout << ptr->a;
}
基類的 public 變成 public,protected 變成 protected,private 仍然是 private。
保護(hù)繼承
基類的 public 和 protected 變成 protected,private 不可訪問。
私有繼承
private(私有繼承):基類的 public 和 protected 變成 private,private 不可訪問。
多繼承下的菱形繼承
sizeof
虛函數(shù)的size
輸出的結(jié)果為:
這是因?yàn)樘摵瘮?shù)引入了虛表,因此需要額外存儲(chǔ)一個(gè)虛表指針,64位系統(tǒng)下size = 8B。
如果再加上一個(gè)int,則為16(需要做到對(duì)齊,因此還補(bǔ)了4B)
多繼承的情況下:
輸出結(jié)果為16,因?yàn)槔^承了A和B,因?yàn)橛袃蓚€(gè)虛指針
普通函數(shù)的size
普通函數(shù)size = 1
struct的size
struct也要遵循內(nèi)存對(duì)齊,對(duì)齊原則是結(jié)構(gòu)體或類的整體大小必須是其最大對(duì)齊數(shù)的整數(shù)倍(最大成員的對(duì)齊值)
因此比如
因?yàn)閏har[]里有一個(gè)’\0’,因此size是6
指針與引用
先來個(gè)很經(jīng)典的題
void GetMemory1(char* p){p = (char*)malloc(100);
}
void Test1(void){char* str =NULL;GetMemory1(str);strcpy(str,"hello");printf(str);
}int main() {Test1();
}
這樣會(huì)導(dǎo)致程序直接崩潰,原因是GetMemory1傳入的函數(shù)是指針。注意,這里進(jìn)行的是值傳遞,也就是說,我們傳入的是str的復(fù)制值,因此在GetMemory1里修改p對(duì)外面的str沒有一點(diǎn)用處。
那么如何修改呢?只需要將GetMemory的參數(shù)改為指針的引用 or 指針的指針即可
指針的引用版:
void GetMemory1(char* p){p = (char*)malloc(100);
}
void Test1(void){char* str =NULL;GetMemory1(str);strcpy(str,"hello");printf(str);
}int main() {Test1();
}
指針的指針版:
void GetMemory1(char** p){*p = (char*)malloc(100);
}
void Test1(void){char* str =NULL;GetMemory1(&str);strcpy(str,"hello");printf(str);
}
再來個(gè)題目
char* GetMemory2(){char p[] = "hello";return p;
}
void Test2(){char* str = NULL;str = GetMemory2();printf(str);
}
這會(huì)導(dǎo)致系統(tǒng)崩潰,因?yàn)?br /> char p[] = “hello”; 是一個(gè)局部數(shù)組,存儲(chǔ)在棧上。
當(dāng) GetMemory2() 結(jié)束后,p 變量的生命周期結(jié)束,它所在的棧內(nèi)存可能被覆蓋或釋放。
str = GetMemory2(); 讓 str 指向了這塊無效的內(nèi)存。
printf(str); 試圖訪問這塊無效的內(nèi)存,導(dǎo)致未定義行為(Undefined Behavior),可能程序崩潰。
但如果我們修改為,此時(shí)內(nèi)存被分配到堆上,就不會(huì)報(bào)錯(cuò)了。注意還需要對(duì)應(yīng)的free
char* p = (char*)malloc(100);