網(wǎng)站的系統(tǒng)建設(shè)方式有哪些內(nèi)容個(gè)人網(wǎng)頁模板
一、名字空間
什么是名字空間
在C語言中定義的全局變量、函數(shù)、結(jié)構(gòu)、聯(lián)合、枚舉、枚舉值、宏都在全局作用域下,所以當(dāng)項(xiàng)目比較龐大時(shí),非常容易造成命名沖突(以模塊名作前綴、后綴),所以C++中選擇把全局作用域進(jìn)行拆分成 子作用域進(jìn)行管理,這些子作用域就是作名字空間。
如何設(shè)計(jì)名字空間
namespace 空間名 {// 子作用域在該作用域中定義全局變量、函數(shù)、結(jié)構(gòu)、聯(lián)合、枚舉、枚舉值...,不會(huì)與全局變量中的命名沖突 } // 此處沒有分號(hào)
如何使用名字空間中的內(nèi)容
方法1:
直接使用空間中的內(nèi)容
空間名::標(biāo)識(shí)符;
#include <iostream> ? int main(int argc,const char* argv[]) {std::cout << "我要使用std中的內(nèi)容" << std::endl; ? ? ? ?return 0; }
方法2:
把空間中的部分內(nèi)容導(dǎo)入到當(dāng)作用域下,一旦導(dǎo)入之后就可以方便的直接使用
using 空間名::標(biāo)識(shí)符;
#include <iostream> ? using std::cout; using std::endl; ? int main(int argc,const char* argv[]) {cout << "我要使用std中的內(nèi)容" << endl; ? ? ? ? ? ? ?return 0; }
方法3:
把空間中的所有內(nèi)容導(dǎo)入到當(dāng)前作用域下
using namespace 空間名;
#include <iostream> ? using namespace std; ? int main(int argc,const char* argv[]) {string str = "string類也定義在std名字空間中";cout << str << endl;return 0; }
注意:C++標(biāo)準(zhǔn)庫中提供的基礎(chǔ)功能的類、對(duì)象都定義在std名字空間中,如:cout、cin、string。
空間合并與空間嵌套
1、編譯器會(huì)把同名的名字空間的內(nèi)容自動(dòng)合并,同名的名字空間就是同一個(gè)作用域,如果同一個(gè)作用域 下有命名沖突編譯就會(huì)報(bào)錯(cuò)。
#include <iostream> using namespace std; ? namespace ns {int num1 = 1234; } ? namespace ns {int num2 = 5678;int num1 = 6666; } ? int main(int argc,const char* argv[]) {using namespace ns;cout << num1 << " " << num2 << endl;return 0; }
2、名字空間中可以再定義名字空間
#include <iostream> using namespace std; ? namespace ns1 {namespace ns2 { ? namespace ns3 {int num = 123456789;}} ? } ? // 嵌套后的名字空間使用起來比較長,可以給內(nèi)部名字空間取別名 namespace ns123=ns1::ns2::ns3; ? int main(int argc,const char* argv[]) {cout << ns1::ns2::ns3::num << endl;cout << ns123::num << endl;return 0; }
匿名名字空間
C++把默認(rèn)的全局作用域當(dāng)作一個(gè)沒有名字的名字空間,也叫匿名名字空間,當(dāng)全局的標(biāo)識(shí)符被屏蔽,可以使用匿名空間的域限定符來指定全局作用域的標(biāo)識(shí)符。
#include <iostream> using namespace std; ? int num = 1234; int main(int argc,const char* argv[]) {int num = 5678;cout << num << endl;cout << ::num << endl;return 0; }
注意:
工作時(shí)盡量不要使用 using namespace 空間名; 這種用法,這就像是把垃圾分類之后,又合并了,如果使用到標(biāo)識(shí)符,一定要 空間名::標(biāo)識(shí)符。
二、面向過程與面向?qū)ο?/h4>
面向過程:
在編程時(shí)重點(diǎn)考慮如何解決問題,以及解決問題的具體步驟。
面向?qū)ο?#xff1a;
在編程時(shí)重點(diǎn)考慮的是"誰"能解決問題(類、結(jié)構(gòu)),以及"它"解決問題時(shí)所需要屬性(成員變量)和功能(成員函數(shù))。
抽象:
把“解決問題者”當(dāng)作思考或觀察對(duì)象,把解決問題所需的具備的屬性和功能羅列出來,這個(gè)步驟叫作抽象。
封裝:
把抽象的結(jié)果(問題所需的具體的屬性和功能),設(shè)置相應(yīng)訪問權(quán)限(public/private/protected),按照C++的語法設(shè)計(jì)成類、結(jié)構(gòu),該過程叫作封裝類,簡稱封裝。
使用封裝好的類、結(jié)構(gòu),實(shí)例化出對(duì)象(定義結(jié)構(gòu)變量、類變量),通過對(duì)象調(diào)用相關(guān)功能(成員函數(shù))配合相關(guān)屬性(成員變量)達(dá)到解決問題的目的。
繼承:
1、在解決一個(gè)問題之前,先考慮現(xiàn)有的類是否能解決部分問題,如果有則繼承該類,在此基礎(chǔ)上進(jìn)行擴(kuò)展,以縮短解決問題的時(shí)間(代碼復(fù)用)。
2、在解決一個(gè)復(fù)雜龐大的問題時(shí),把問題拆分成若干個(gè)小問題,每個(gè)小問題實(shí)現(xiàn)一個(gè)類去解決,最后把這若干個(gè)類通過繼承進(jìn)行匯總,達(dá)到解決問題的目的,這個(gè)方式可以降低問題的規(guī)模在難度,也方便團(tuán)隊(duì)分工、協(xié)作。
多態(tài):
語句的多種形態(tài),同樣的語句根據(jù)環(huán)境或參數(shù)的不同,有不同的功能,這就叫多態(tài)。
多態(tài)可以分為:
編譯時(shí)多態(tài),編譯器在編譯代碼時(shí)根據(jù)語句的參數(shù)、環(huán)境不同,能翻譯出具有不同功能的二進(jìn)制指令,例如:調(diào)用重載的函數(shù),cin、cout的自動(dòng)類型識(shí)別,模板技術(shù)(后續(xù)講解)。
運(yùn)行時(shí)多態(tài),語句只在程序運(yùn)行時(shí),才能確定執(zhí)行那種功能,一般指的是類多態(tài),后續(xù)再詳細(xì)講解。
#include <iostream> using namespace std; ? void func1(void) {cout << "我是func1函數(shù)" << endl; } ? void func2(void) {cout << "我是func2函數(shù)" << endl; } ? int main() {void (*fp)(void);int cmd;cin >> cmd;if(cmd % 2)fp = func1;elsefp = func2;fp(); }
三、類和對(duì)象
什么是類
把抽象結(jié)果(利用面向?qū)ο蟮乃季S模式,思考、觀察出的結(jié)果),使用用C++的語法封裝出一種類似結(jié)構(gòu)的自定義數(shù)據(jù)類型(復(fù)合數(shù)據(jù)類型)。
如何設(shè)計(jì)類
struct 結(jié)構(gòu)名 {成員函數(shù); // 結(jié)構(gòu)的成員默認(rèn)訪問權(quán)限是public成員變量; };class 類名 {成員變量; // 結(jié)構(gòu)的成員默認(rèn)訪問權(quán)限是private成員函數(shù); };注意:在C++中類的結(jié)構(gòu)除了成員的默認(rèn)訪問權(quán)限不同,沒有任何區(qū)別(大師兄說的)。
訪問限制符
使用以下關(guān)鍵字修改結(jié)構(gòu)、類的成員,管理它們的訪問權(quán)限:
private: 私有的,被它修飾的成員,只能在類的成員函數(shù)內(nèi)使用。 protected: 保護(hù)的,被它修飾的成員,只能在類、子類的成員函數(shù)內(nèi)使用。 public: 公開的,被修飾的成員,可以在任何位置使用。
#include <iostream> using namespace std;struct Student {void in(void){ cout << "請(qǐng)輸入學(xué)生的學(xué)號(hào)、姓名、年齡、成績:"; cin >> id >> name >> age >> score;} void out(void){ // 學(xué)號(hào):10010 姓名:hehe 年齡:18 成績:100cout << "學(xué)號(hào):" << id << " 姓名:" << name << " 年齡:" << age << " 成績:" << score << endl;} private:int id; char name[20];short age;float score; };class Student {int id; char name[20];short age;float score; public:void in(void){ cout << "請(qǐng)輸入學(xué)生的學(xué)號(hào)、姓名、年齡、成績:"; cin >> id >> name >> age >> score;} void out(void){ // 學(xué)號(hào):10010 姓名:hehe 年齡:18 成績:100cout << "學(xué)號(hào):" << id << " 姓名:" << name << " 年齡:" << age << " 成績:" << score << endl;} };int main(int argc,const char* argv[]) {Student stu;stu.in();stu.out();return 0; }
什么是類對(duì)象
使用設(shè)計(jì)好的類(結(jié)構(gòu))這種數(shù)據(jù)類型,定義出的類變量在面向?qū)ο缶幊陶Z言中被稱為對(duì)象(結(jié)構(gòu)變量),創(chuàng)建類對(duì)象的行為也被稱為實(shí)例化對(duì)象。
#include <iostream> using namespace std;class Student {int id; char name[20];short age;float score; public:void in(void){ cout << "請(qǐng)輸入學(xué)生的學(xué)號(hào)、姓名、年齡、成績:"; cin >> id >> name >> age >> score;} void out(void){ // 學(xué)號(hào):10010 姓名:hehe 年齡:18 成績:100cout << "學(xué)號(hào):" << id << " 姓名:" << name << " 年齡:" << age << " 成績:" << score << endl;} };Student stu; // 在bss內(nèi)存段上實(shí)例化對(duì)象 int main(int argc,const char* argv[]) {Student stu; // 在stack內(nèi)存段實(shí)例化對(duì)象Student* stup = new Student; // 在heap內(nèi)存段實(shí)例化對(duì)象 }
類的聲明與實(shí)現(xiàn)分開
如果類的內(nèi)容不多,一般會(huì)選擇只定義一個(gè)頭文件,以類名作為文件名。
#ifndef STUDENT_H #define STUDENT_Hclass 類名 {// 定義成員變量 public:// 定義成員函數(shù) };#endif//STUDENT_H
如果類的內(nèi)容比較多,會(huì)選擇把類的聲明與定義分開,頭文件負(fù)責(zé)類的聲明,源文件負(fù)責(zé)類的實(shí)現(xiàn)。
#ifndef STUDENT_H #define STUDENT_Hclass 類名 {// 定義成員變量 public:// 聲明成員函數(shù)void 函數(shù)名(參數(shù)列表); };#endif//STUDENT_H
#include "student.h"void 類名::函數(shù)名(參數(shù)列表) {}
練習(xí):實(shí)現(xiàn)C++版的通訊錄。
四、構(gòu)造函數(shù)與析構(gòu)函數(shù)
構(gòu)造函數(shù)
1、什么構(gòu)造函數(shù)
類、結(jié)構(gòu)、聯(lián)合中的特殊成員函數(shù),與類名、結(jié)構(gòu)名、聯(lián)合名同的成員函數(shù),沒有返回值。
class 類名 { public:類名(參數(shù)列表){} };
2、何時(shí)調(diào)用構(gòu)造函數(shù)
當(dāng)創(chuàng)建類對(duì)象時(shí)(實(shí)例化對(duì)象)會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù)。
int main(int argc,const char* argv[]) {// 調(diào)用無參構(gòu)造Student stu;Student* stup = new Student;// 調(diào)用有參構(gòu)造Student stu1(10010,"hehe",'w',18,98);Student* stup1 = new Student(10011,"xixi",'m',20,95);// 調(diào)用有參構(gòu)造,c11語法標(biāo)準(zhǔn)才支持,-std=c++11Student stu2 = {10010,"hehe",'w',18,98};return 0; }
3、在構(gòu)造函數(shù)中應(yīng)該做什么
構(gòu)造函數(shù)負(fù)責(zé)創(chuàng)建使用對(duì)象的環(huán)境,一般構(gòu)造函數(shù)中負(fù)責(zé):
1、給成員變量初始化
2、給指針成員分配內(nèi)存
3、從文件、網(wǎng)絡(luò)、數(shù)據(jù)庫加載數(shù)據(jù)
4、完成一些準(zhǔn)備工作
4、實(shí)現(xiàn)構(gòu)造函數(shù)要注意的問題
在創(chuàng)建類對(duì)象時(shí),一定會(huì)調(diào)用構(gòu)造函數(shù),如果類中沒有顯式實(shí)現(xiàn)構(gòu)造函數(shù),編譯器會(huì)自動(dòng)生成一個(gè)無參的什么都不做的構(gòu)造函數(shù)。
如果顯式實(shí)現(xiàn)了有參構(gòu)造函數(shù),那么編譯器就不會(huì)再生成無參構(gòu)造。
注意:在使用new[] 創(chuàng)建n個(gè)對(duì)象時(shí),無法保證給所有的類對(duì)象都單獨(dú)提供參數(shù),去調(diào)用有參構(gòu)造,那么必然需要調(diào)用無參構(gòu)造,此時(shí)如果沒有顯式實(shí)現(xiàn)無參構(gòu)造,編譯就會(huì)出錯(cuò)。
方法1:
class Student { public:Student() {} // 極簡無參構(gòu)造 };
方法2:
給有參構(gòu)造函數(shù)的所有成員都設(shè)置默認(rèn)形參,當(dāng)需要調(diào)用無參構(gòu)造時(shí),會(huì)自動(dòng)使用默認(rèn)參數(shù)調(diào)用有參構(gòu)造。
// 無參構(gòu)造未必?zé)o參 class Student {... public:Student(int _id=0,const string& _name="",char _sex='w',short _age=0,float _score=0){id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有參構(gòu)造" << endl;} };
5、explicit關(guān)鍵字的作用
如果類中有單參的構(gòu)造函數(shù),那么它的參數(shù)類型數(shù)據(jù)就能隱藏提升為類對(duì)象,如果不使用該功能,可以在單參構(gòu)造函數(shù)的前面加 explicit 關(guān)鍵字,參數(shù)類型數(shù)據(jù)就不能再隱藏提升為類對(duì)象。
總結(jié):explicit關(guān)鍵字的作用就是禁止單參構(gòu)造函數(shù)的類型提升功能。
#include <iostream> using namespace std;class Test {int num; public:[explicit] Test(int _num){ num = _num;} };void func(Test t) {cout << "我被調(diào)用了" << endl; }int main(int argc,const char* argv[]) {func(1234); }
析構(gòu)函數(shù):
1、什么析構(gòu)函數(shù)
類、結(jié)構(gòu)、聯(lián)合中的特殊成員函數(shù),在類名、結(jié)構(gòu)名、聯(lián)合的前面加~,就是析構(gòu)函數(shù),沒有返回也沒有參數(shù)。
struct Student {int id; string name;char sex;short age;float score; public:Student(void){cout << "我是無參構(gòu)造函數(shù)" << endl;}Student(int _id,const string& _name,char _sex,short _age,float _score){ id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有參構(gòu)造" << endl;} ~Student(void){ cout << "我是析構(gòu)函數(shù)" << endl;} };
2、在析構(gòu)函數(shù)中應(yīng)該做什么
析構(gòu)函數(shù)負(fù)責(zé)對(duì)象銷毀時(shí)的收尾工作,一般構(gòu)造函數(shù)中負(fù)責(zé):
1、釋放指針成員指向的堆內(nèi)存
2、往文件中、數(shù)據(jù)庫保存數(shù)據(jù)
3、何時(shí)調(diào)用析構(gòu)函數(shù)
1、當(dāng)類對(duì)象離開它所在的作用域時(shí),系統(tǒng)會(huì)自動(dòng)銷毀類對(duì)象,并自動(dòng)調(diào)用析構(gòu)函數(shù)。
#include <iostream> using namespace std;struct Student {int id;string name;char sex;short age;float score; public:Student(void){cout << "我是無參構(gòu)造函數(shù)" << endl;}Student(int _id,const string& _name,char _sex,short _age,float _score){id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有參構(gòu)造" << endl;}~Student(void){cout << "我是析構(gòu)函數(shù)" << endl;} };int main(int argc,const char* argv[]) {do{// 當(dāng)創(chuàng)建類對(duì)象時(shí),自動(dòng)調(diào)用構(gòu)造函數(shù),當(dāng)對(duì)象離開它的作用域時(shí),會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)Student stu;}while(0);cout << "-----------" << endl; }
2、當(dāng)使用delete或delete[] 釋放堆內(nèi)存上的類對(duì)象時(shí),會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)(必須使用delete釋放)。
#include <iostream> using namespace std;struct Student {int id;string name;char sex;short age;float score; public:Student(void){cout << "我是無參構(gòu)造函數(shù)" << endl;}Student(int _id,const string& _name,char _sex,short _age,float _score){id = _id;name = _name;sex = _sex;age = _age;score = _score;cout << "我是有參構(gòu)造" << endl;}~Student(void){cout << "我是析構(gòu)函數(shù)" << endl;} };int main(int argc,const char* argv[]) {// 使用new 或 new[] 在堆內(nèi)存上創(chuàng)建類對(duì)象時(shí)會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù)Student* stup = new Student;Student* stus = new Student[10];// 類對(duì)象的個(gè)數(shù),也是執(zhí)行構(gòu)造、析構(gòu)函數(shù)的次數(shù)cout << *((int*)stus-1) << endl;// 使用delete 或 delete[] 釋放堆內(nèi)存上的類對(duì)象時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù)delete stup;delete[] stus;// 注意:使用new創(chuàng)建的就使用delete釋放,使用new[]創(chuàng)建的就使用delete[]釋放,不能混用return 0; }
4、析構(gòu)函數(shù)要注意的問題
如果沒有顯式實(shí)現(xiàn)析構(gòu)函數(shù),那么編譯器會(huì)自動(dòng)生成一個(gè)什么都不做的析構(gòu)函數(shù)。
如果構(gòu)造函數(shù)中使用new、malloc分配的堆內(nèi)存,就一定要顯式實(shí)現(xiàn)析構(gòu)函數(shù),并在析構(gòu)函數(shù)中釋放堆內(nèi)存,否則就會(huì)造成內(nèi)存泄漏。
五、初始化列表與const成員
const成員
使用const修飾的類、結(jié)構(gòu)、聯(lián)合的成員變量,在類對(duì)象創(chuàng)建完成前一定要初始化。
不能在構(gòu)造函數(shù)中初始化const成員,因?yàn)閳?zhí)行構(gòu)造函數(shù)時(shí),類對(duì)象已經(jīng)創(chuàng)建完成,只有類對(duì)象創(chuàng)建完成才能調(diào)用成員函數(shù),構(gòu)造函數(shù)雖然特殊但也是成員函數(shù)。
在定義const成員時(shí)進(jìn)行初始化,該語法只有在C11語法標(biāo)準(zhǔn)下才支持。
初始化列表
在構(gòu)造函數(shù)小括號(hào)后面,主要用于給const成員初始化的一種特殊語法,也可以給普通成員初始化(可以解決參數(shù)名與成員變量名同名的問題)。
注意:如果有成員是類、結(jié)構(gòu)、聯(lián)合類型的,還可以在初始化列表中顯式調(diào)用成員的構(gòu)造函數(shù),還可以調(diào)用父類的構(gòu)造函數(shù)。
class 類名 {成員變量; public:構(gòu)造函數(shù)(參數(shù)列表):成員變量(初始值),成員變量(初始值),...{} };
#include <iostream> using namespace std;class Test {// 可以使用,但只有C11標(biāo)準(zhǔn)才支持// const int num = 1234;const int num; public:Test(int num=0):num(num){ cout << "我是帶初始化列表的構(gòu)造函數(shù)" << endl;} void show(void){ cout << "const num = " << num << endl;} }; int main(int argc,const char* argv[]) {Test t(123456789);t.show();return 0; }