<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          騰訊C++后臺(tái)開(kāi)發(fā)面試筆試知識(shí)點(diǎn)參考筆記

          共 2360字,需瀏覽 5分鐘

           ·

          2020-10-10 08:32

          文章是由我筆試面試騰訊筆記整理而來(lái),主要是針對(duì)面試的C++后臺(tái)開(kāi)發(fā)崗位,涵蓋了大部分C++后臺(tái)開(kāi)發(fā)相關(guān)可能會(huì)考察和被問(wèn)到的技術(shù)點(diǎn)。

          自認(rèn)為這篇筆記是比較全面的總結(jié),不管你是已經(jīng)工作準(zhǔn)備參加社招,還是在校學(xué)生準(zhǔn)備參加校招,筆記都可以作為技術(shù)面試準(zhǔn)備階段參考查閱,查缺補(bǔ)漏。

          筆記是基礎(chǔ)C++知識(shí)點(diǎn)總結(jié),沒(méi)有過(guò)多的闡述后臺(tái)開(kāi)發(fā)的系統(tǒng)架構(gòu)和分布式后臺(tái)服務(wù)設(shè)計(jì)相關(guān),還有c++11新特性,這些筆試面試也會(huì)被問(wèn)到但不在這篇討論范圍,可以關(guān)注我后面有時(shí)間再補(bǔ)上。

          閱讀提示

          文章約12839字,閱讀時(shí)長(zhǎng)預(yù)計(jì)33分鐘。建議關(guān)注收藏方便回頭查閱。


          gdb調(diào)試命令

          step和next的區(qū)別?

          當(dāng)前l(fā)ine有函數(shù)調(diào)用的時(shí)候,next會(huì)直接執(zhí)行到下一句 ,step會(huì)進(jìn)入函數(shù).

          查看內(nèi)存

          (gdb)p &a //打印變量地址

          (gdb)x 0xbffff543 //查看內(nèi)存單元內(nèi)變量

          0xbffff543: 0x12345678

          (gdb) x /4xb 0xbffff543 //單字節(jié)查看4個(gè)內(nèi)存單元變量的值

          0xbffff543: 0x78 0x56 0x34 0x12

          多線程調(diào)試

          (gdb) info threads:查看GDB當(dāng)前調(diào)試的程序的各個(gè)線程的相關(guān)信息

          (gdb) thread threadno:切換當(dāng)前線程到由threadno指定的線程

          break filename:linenum thread all ? 在所有線程相應(yīng)行設(shè)置斷點(diǎn),注意如果主線程不會(huì)執(zhí)行到該行,并且啟動(dòng)all-stop模式,主線程執(zhí)行n或s會(huì)切換過(guò)去

          set scheduler-locking off|on\step ? ?默認(rèn)off,執(zhí)行s或c其它線程也同步執(zhí)行。on,只有當(dāng)前線程執(zhí)行。step,只有當(dāng)前線程執(zhí)行

          show scheduler-locking ? ? ? ? ?顯示當(dāng)前模式

          thread apply all command ? ? ? ?每個(gè)線程執(zhí)行同意命令,如bt?;蛘遲hread apply 1 3 bt,即線程1,3執(zhí)行bt。

          查看調(diào)用堆棧

          (gdb)bt

          (gdb)f 1 幀簡(jiǎn)略信息

          (gdb)info f 1 幀詳細(xì)信息

          斷點(diǎn)

          b test.cpp:11

          b test.cpp:main

          gdb attach 調(diào)試方法:

          gdb->file xxxx->attach pid->這時(shí)候進(jìn)程是停止的->c 繼續(xù)運(yùn)行

          帶參數(shù)調(diào)試

          輸入?yún)?shù)命令set args 后面加上程序所要用的參數(shù),注意,不再帶有程序名,直接加參數(shù),如:

          (gdb)set args -l a -C abc

          list命令

          list linenum  顯示程序第linenum行的周圍的程序

          list function  顯示程序名為function的函數(shù)的源程序


          static關(guān)鍵字的作用


          軟硬鏈接

          ln -s 源文件 目標(biāo)文件, ln -s / /home/good/linkname鏈接根目錄/到/home/good/linkname

          1、軟鏈接就是:“l(fā)n –s 源文件 目標(biāo)文件”,只會(huì)在選定的位置上生成一個(gè)文件的鏡像,不會(huì)占用磁盤空間,類似于windows的快捷方式。

          2、硬鏈接ln源文件目標(biāo)文件,沒(méi)有參數(shù)-s, 會(huì)在選定的位置上生成一個(gè)和源文件大小相同的文件,無(wú)論是軟鏈接還是硬鏈接,文件都保持同步變化。


          函數(shù)指針 ?

          函數(shù)指針 int (*func)(int, int)

          函數(shù)指針數(shù)組 int (*funcArry[10])(int, int)

          const int* p; 指向const int的指針

          int const* p; 同上

          int* const p; const指針

          設(shè)計(jì)模式

          單例模式

          觀察者模式(也叫發(fā)布訂閱模式)

          工廠模式 三種:簡(jiǎn)單工廠模式、工廠方法模式、抽象工廠模式

          為什么要用工廠模式?

          原因就是對(duì)上層的使用者隔離對(duì)象創(chuàng)建的過(guò)程;或者是對(duì)象創(chuàng)建的過(guò)程復(fù)雜,使用者不容易掌握;或者是對(duì)象創(chuàng)建要滿足某種條件,這些條件是業(yè)務(wù)的需求也好,是系統(tǒng)約束也好,沒(méi)有必要讓上層使用者掌握,增加別人開(kāi)發(fā)的難度。所以,到這時(shí)我們應(yīng)該清楚了,無(wú)論是工廠模式,還是上面的戰(zhàn)友說(shuō)的開(kāi)閉原則,都是為了隔離一些復(fù)雜的過(guò)程,使得這些復(fù)雜的過(guò)程不向外暴露,如果暴露了這些過(guò)程,會(huì)對(duì)使用者增加麻煩,這也就是所謂的團(tuán)隊(duì)合作。

          數(shù)據(jù)結(jié)構(gòu)

          各種排序算法

          堆排序

          關(guān)鍵:1.初始建堆從最后一個(gè)非葉節(jié)點(diǎn)開(kāi)始調(diào)整 2.篩選從頂點(diǎn)開(kāi)始往下調(diào)整

          通俗易懂的快排

          二叉樹(shù)定理

          度為2節(jié)點(diǎn)數(shù) = 葉子節(jié)點(diǎn)數(shù) - 1

          證明:樹(shù)枝數(shù)=節(jié)點(diǎn)數(shù)-1, n00 +n11 +n2*2 = n0+n1+n2-1 (n0代表度為0的節(jié)點(diǎn)數(shù),以此類推)


          互斥鎖

          pthread_mutex_t m_mutex;
          pthread_mutex_init(&m_mutex, NULL)等效于pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
          pthread_mutex_lock(&m_mutex);
          pthread_mutex_unlock(&m_mutex)
          pthread_mutex_destroy(&m_mutex)
          int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
          bool g_flag = false;
          void* t1(void* arg)
          {
          ?cout << "create t1 thread success" << endl;
          ?pthread_mutex_lock(&m_mutex);
          ?g_flag = true;
          ?pthread_mutex_unlock(&m_mutex);
          }

          void* t2(void* arg)
          {
          ?cout << "create t2 thread success" << endl;
          ?pthread_mutex_lock(&m_mutex);
          ?g_flag = false;
          ?pthread_mutex_unlock(&m_mutex);
          }

          int main(int argc, char* argv[])
          {
          ?pthread_t tid1, tid2;
          ?pthread_create(&tid1, NULL, t1, NULL);
          ?sleep(2);
          ?pthread_create(&tid2, NULL, t2, NULL);
          ?pthread_join(tid1, NULL);
          ?pthread_join(tid2, NULL);
          }


          大小端轉(zhuǎn)換

          #define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) | \
          ? ? ? ? ? ? ? ? ? ? (((uint32)(A) & 0x00ff0000) >> 8) | \
          ? ? ? ? ? ? ? ? ? ? (((uint32)(A) & 0x0000ff00) << 8) | \
          ? ? ? ? ? ? ? ? ? ? (((uint32)(A) & 0x000000ff) << 24))


          io多路復(fù)用

          為什么 IO 多路復(fù)用要搭配非阻塞IO

          設(shè)置非阻塞 io fcntl(sockfd, F_SETFL, O_NONBLOCK);

          select

          int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

          void FD_CLR(int fd, fd_set *set);

          int FD_ISSET(int fd, fd_set *set);

          void FD_SET(int fd, fd_set *set);

          void FD_ZERO(fd_set *set);

          fd_set rdfds;
          struct timeval tv;
          int ret;
          FD_ZERO(&rdfds);
          FD_SET(socket, &rdfds);
          tv.tv_sec = 1;
          tv.tv_uses = 500;
          ret = select (socket + 1, %rdfds, NULL, NULL, &tv);
          if(ret < 0) perror (“select”);
          else if (ret = = 0) printf(“time out”);
          else
          {
          printf(“ret = %d/n”,ret);
          if(FD_ISSET(socket, &rdfds)){
          /* 讀取socket句柄里的數(shù)據(jù) */
          }注意select函數(shù)的第一個(gè)參數(shù),是所有加入集合的句柄值的最大那個(gè)那個(gè)值還要加1.比如我們創(chuàng)建了3個(gè)句柄;


          poll實(shí)現(xiàn)

          poll的實(shí)現(xiàn)和select非常相似,只是描述fd集合的方式不同,poll使用pollfd結(jié)構(gòu)而不是select的fd_set結(jié)構(gòu),其他的都差不多,管理多個(gè)描述符也是進(jìn)行輪詢,根據(jù)描述符的狀態(tài)進(jìn)行處理,但是poll沒(méi)有最大文件描述符數(shù)量的限制。poll和select同樣存在一個(gè)缺點(diǎn)就是,包含大量文件描述符的數(shù)組被整體復(fù)制于用戶態(tài)和內(nèi)核的地址空間之間,而不論這些文件描述符是否就緒,它的開(kāi)銷隨著文件描述符數(shù)量的增加而線性增大。

          epoll原理

          https://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

          #include 
          int epoll_create(int size);

          int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

          int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

          epoll對(duì)文件描述符的操作有兩種模式:LT(level trigger)和ET(edge trigger)。LT模式是默認(rèn)模式,LT模式與ET模式的區(qū)別如下:

          LT模式:當(dāng)epoll_wait檢測(cè)到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序可以不立即處理該事件。下次調(diào)用epoll_wait時(shí),會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。? ?

          ET模式:當(dāng)epoll_wait檢測(cè)到描述符事件發(fā)生并將此事件通知應(yīng)用程序,應(yīng)用程序必須立即處理該事件。如果不處理,下次調(diào)用epoll_wait時(shí),不會(huì)再次響應(yīng)應(yīng)用程序并通知此事件。

          ET模式在很大程度上減少了epoll事件被重復(fù)觸發(fā)的次數(shù),因此效率要比LT模式高。epoll工作在ET模式的時(shí)候,

          必須使用非阻塞套接口,以避免由于一個(gè)文件句柄的阻塞讀/阻塞寫操作把處理多個(gè)文件描述符的任務(wù)餓死。

          Epoll ET模型下,為什么每次EPOLLIN事件都會(huì)帶一次EPOLLOUT事件:https://bbs.csdn.net/topics/390630226

          udp套接字

          #include 

          ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags, ?const struct sockaddr *destaddr, socklen_t addrlen);

          ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags, ?struct sockaddr *addr, socklen_t *addrlen);


          網(wǎng)絡(luò)套接字

          udp原理與套接字 ? ? ? ? ? ? ? ?

          udp服務(wù)端:

          sockListener=socket(AF_INET,SOCK_DGRAM,0)

          bind(sockListener,(struct sockaddr*)&addrListener,sizeof(addrListener))

          nMsgLen=recvfrom(sockListener,szBuf,1024,0,(struct sockaddr*)&addrClient,&addrLen) ?

          udp客戶端

          sockClient=socket(AF_INET,SOCK_DGRAM,0);
          bind(sockClient,(struct sockaddr*)&addrLocal,sizeof(addrLocal))
          FD_ZERO(&setHold);
          FD_SET(STDIN_FILENO,&setHold);
          FD_SET(sockClient,&setHold);
          cout<<"you can type in sentences any time"<<endl;
          while(true)
          {
          ? ?setTest=setHold;
          ? ?nReady=select(sockClient+1,&setTest,NULL,NULL,NULL);
          ? ?if(FD_ISSET(0,&setTest))
          ? {
          ? ? ? ?nMsgLen=read(0,szMsg,1024);
          ? ? ? ?write(sockClient,szMsg,nMsgLen);
          ? }
          ? ?if(FD_ISSET(sockClient,&setTest))
          ? {
          ? ? ? ?nMsgLen=read(sockClient,szRecv,1024);
          ? ? ? ?szRecv[nMsgLen]='\0';
          ? ? ? ?cout<<"read:"<<szRecv<<endl;
          ? }
          } ? ?

          UDP中使用 connect 函數(shù)成為已連接的套接字

          已連接 UDP 套接字 相對(duì)于 未連接 UDP 套接字 會(huì)有以下的變化:

          1. 不能給輸出操作指定目的 IP 地址和端口號(hào)(因?yàn)檎{(diào)用 connect 函數(shù)時(shí)已經(jīng)指定),即不能使用 sendto 函數(shù),而是使用 write 或 send 函數(shù)。寫到已連接 UDP 套接字上的內(nèi)容都會(huì)自動(dòng)發(fā)送到由 connect 指定的協(xié)議地址;

          2. 不必使用 recvfrom 函數(shù)以獲悉數(shù)據(jù)報(bào)的發(fā)送者,而改用 read、recv 或 recvmsg 函數(shù)。在一個(gè)已連接 UDP 套接字上,由內(nèi)核為輸入操作返回的數(shù)據(jù)報(bào)只有那些來(lái)自 connect 函數(shù)所指定的協(xié)議地址的數(shù)據(jù)報(bào)。目的地為這個(gè)已連接 UDP 套接字的本地協(xié)議地址,發(fā)源地不是該套接字早先 connect 到的協(xié)議地址的數(shù)據(jù)報(bào),不會(huì)投遞到該套接字。即只有發(fā)源地的協(xié)議地址與 connect 所指定的地址相匹配才可以把數(shù)據(jù)報(bào)傳輸?shù)皆撎捉幼?。這樣已連接 UDP 套接字只能與一個(gè)對(duì)端交換數(shù)據(jù)報(bào);

          3. 由已連接 UDP 套接字引發(fā)的異步錯(cuò)誤會(huì)返回給它們所在的進(jìn)程,而未連接 UDP 套接字不會(huì)接收任何異步錯(cuò)誤;

          tcp套接字

          服務(wù)端:

          listenfd = socket(AF_INET , SOCK_STREAM , 0)

          bind(listenfd , (struct sockaddr*)&servaddr , sizeof(servaddr))

          listen(listenfd , LISTENQ)

          connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen))

          n = read(connfd , buff , MAX_LINE)

          write(connfd , buff , n)

          客戶端:

          sockfd = socket(AF_INET , SOCK_STREAM , 0)

          connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))

          write(sockfd , sendline , strlen(sendline))


          IP分片與重組

          參考1

          參考2

          MTU是1500是指的以太網(wǎng)的MTU,可以用 netstat -i 命令查看這個(gè)值。如果IP層有數(shù)據(jù)包要傳,而且數(shù)據(jù)包的長(zhǎng)度超過(guò)了MTU,

          那么IP層就要對(duì)數(shù)據(jù)包進(jìn)行分片(fragmentation)操作,使每一片的長(zhǎng)度都小于或等于MTU。

          我們假設(shè)要傳輸一個(gè)UDP數(shù)據(jù)包,以太網(wǎng)的MTU為1500字節(jié),一般IP首部為20字節(jié),UDP首部為8字節(jié),數(shù)據(jù)的凈荷(payload)

          部分預(yù)留是1500-20-8=1472字節(jié)。如果數(shù)據(jù)部分大于1472字節(jié),就會(huì)出現(xiàn)分片現(xiàn)象,

          偏移量的單位為8Byte

          以ID標(biāo)示是不是同一個(gè)分片,以偏移量標(biāo)示在報(bào)文里的位置,每個(gè)不完整的ID報(bào)文有一個(gè)等待計(jì)時(shí)器,到時(shí)丟棄IP層不保證能夠送達(dá),

          如果丟了上層自己處理參考rfc 791

          IP報(bào)文長(zhǎng)度單位口訣

          4字節(jié)單位- 首部長(zhǎng)度單位 1字節(jié)單位-總長(zhǎng)度單位 ?8字節(jié)單位-片偏移單位

          STL容器

          vector與list

          1.vector數(shù)據(jù)結(jié)構(gòu)

          vector和數(shù)組類似,擁有一段連續(xù)的內(nèi)存空間,并且起始地址不變。

          因此能高效的進(jìn)行隨機(jī)存取,時(shí)間復(fù)雜度為o(1);

          但因?yàn)閮?nèi)存空間是連續(xù)的,所以在進(jìn)行插入和刪除操作時(shí),會(huì)造成內(nèi)存塊的拷貝,時(shí)間復(fù)雜度為o(n)。

          另外,當(dāng)數(shù)組中內(nèi)存空間不夠時(shí),會(huì)重新申請(qǐng)一塊內(nèi)存空間并進(jìn)行內(nèi)存拷貝。

          2.list數(shù)據(jù)結(jié)構(gòu)

          list是由雙向鏈表實(shí)現(xiàn)的,因此內(nèi)存空間是不連續(xù)的。

          只能通過(guò)指針訪問(wèn)數(shù)據(jù),所以list的隨機(jī)存取非常沒(méi)有效率,時(shí)間復(fù)雜度為o(n);

          但由于鏈表的特點(diǎn),能高效地進(jìn)行插入和刪除。


          Vector動(dòng)態(tài)內(nèi)存分配

          這個(gè)問(wèn)題其實(shí)很簡(jiǎn)單,在調(diào)用push_back時(shí),若當(dāng)前容量已經(jīng)不能夠放入心得元素(capacity=size),那么vector會(huì)重新申請(qǐng)一塊內(nèi)存,把之前的內(nèi)存里的元素拷貝到新的內(nèi)存當(dāng)中,然后把push_back的元素拷貝到新的內(nèi)存中,最后要析構(gòu)原有的vector并釋放原有的內(nèi)存。所以說(shuō)這個(gè)過(guò)程的效率是極低的,為了避免頻繁的分配內(nèi)存,C++每次申請(qǐng)內(nèi)存都會(huì)成倍的增長(zhǎng),例如之前是4,那么重新申請(qǐng)后就是8,以此類推。當(dāng)然不一定是成倍增長(zhǎng),比如在我的編譯器環(huán)境下實(shí)測(cè)是0.5倍增長(zhǎng),之前是4,重新申請(qǐng)后就是6

          TinySTL


          預(yù)處理指令

          #pragma once 防止頭文件重復(fù)引用

          一字節(jié)對(duì)齊

          #pragma pack(push, 1)

          #pragma pack(pop)

          class面向?qū)ο?/span>

          類繼承

          class LayerManager : public ILayerManager{};

          為什么析構(gòu)函數(shù)要是虛函數(shù)?

          基類指針可以指向派生類的對(duì)象(多態(tài)性),如果刪除該指針delete []p;就會(huì)調(diào)用該指針指向的派生類析構(gòu)函數(shù),而派生類的析構(gòu)函數(shù)又自動(dòng)調(diào)用基類的析構(gòu)函數(shù),這樣整個(gè)派生類的對(duì)象完全被釋放。如果析構(gòu)函數(shù)不被聲明成虛函數(shù),則編譯器實(shí)施靜態(tài)綁定,在刪除基類指針時(shí),只會(huì)調(diào)用基類的析構(gòu)函數(shù)而不調(diào)用派生類析構(gòu)函數(shù),這樣就會(huì)造成派生類對(duì)象析構(gòu)不完全。所以,將析構(gòu)函數(shù)聲明為虛函數(shù)是十分必要的。


          覆蓋虛函數(shù)機(jī)制

          在某些情況下,希望覆蓋虛函數(shù)機(jī)制并強(qiáng)制函數(shù)調(diào)用使用虛函數(shù)的特定版

          本,這里可以使用作用域操作符:

          Item_base *baseP = &derived;

          // calls version from the base class regardless of the dynamic type of baseP
          double d = baseP->Item_base::net_price(42);

          這段代碼強(qiáng)制將 net_price 調(diào)用確定為 Item_base 中定義的版本,該調(diào)用

          將在編譯時(shí)確定。只有成員函數(shù)中的代碼才應(yīng)該使用作用域操作符覆蓋虛函數(shù)機(jī)制。

          為什么會(huì)希望覆蓋虛函數(shù)機(jī)制?最常見(jiàn)的理由是為了派生類虛函數(shù)調(diào)用基類中的版本。在這種情況下,基類版本可以完成繼承層次中所有類型的公共任務(wù),而每個(gè)派生類型只添加自己的特殊工作。

          例如,可以定義一個(gè)具有虛操作的 Camera 類層次。Camera 類中的 display函數(shù)可以顯示所有的公共信息,派生類(如 PerspectiveCamera)可能既需要顯示公共信息又需要顯示自己的獨(dú)特信息??梢燥@式調(diào)用 Camera 版本以顯示公共信息,而不是在 PerspectiveCamera 的 display 實(shí)現(xiàn)中復(fù)制 Camera 的操作。

          在這種情況下,已經(jīng)確切知道調(diào)用哪個(gè)實(shí)例,因此,不需要通過(guò)虛函數(shù)機(jī)制。派生類虛函數(shù)調(diào)用基類版本時(shí),必須顯式使用作用域操作符。如果派生類函數(shù)忽略了這樣做,則函數(shù)調(diào)用會(huì)在運(yùn)行時(shí)確定并且將是一個(gè)自身調(diào)用,從而導(dǎo)致無(wú)窮遞歸。


          名字沖突與繼承

          雖然可以直接訪問(wèn)基類成員,就像它是派生類成員一樣,但是成員保留了它的基類成員資格。一般我們并不關(guān)心是哪個(gè)實(shí)際類包含成員,通常只在基類和派生類共享同一名字時(shí)才需要注意。

          與基類成員同名的派生類成員將屏蔽對(duì)基類成員的直接訪問(wèn)。

          struct Base
          {
          ? ?Base(): mem(0) { }
          ? ?protected:
          ? ?int mem;
          };

          struct Derived : Base
          {
          ? ?Derived(int i): mem(i) { } // initializes Derived::mem
          ? ?int get_mem() { return mem; } // returns Derived::mem
          ? ?protected:
          ? ?int mem; // hides mem in the base
          };

          get_mem 中對(duì) mem 的引用被確定為使用 Derived 中的名字。如果編寫如下代碼:
          Derived d(42);
          cout << d.get_mem() << endl; // prints 42

          則輸出將是 42。

          使用作用域操作符訪問(wèn)被屏蔽成員

          可以使用作用域操作符訪問(wèn)被屏蔽的基類成員:

          struct Derived : Base 
          {
          int get_base_mem() { return Base::mem; }
          };

          作用域操作符指示編譯器在 Base 中查找 mem。

          設(shè)計(jì)派生類時(shí),只要可能,最好避免與基類數(shù)據(jù)成員的名字相同


          類成員函數(shù)的重載、覆蓋和隱藏區(qū)別?

          a.成員函數(shù)被重載的特征:

          (1)相同的范圍(在同一個(gè)類中);

          (2)函數(shù)名字相同;

          (3)參數(shù)不同;

          (4)virtual 關(guān)鍵字可有可無(wú)。

          b.覆蓋是指派生類函數(shù)覆蓋基類函數(shù),特征是:

          (1)不同的范圍(分別位于派生類與基類);

          (2)函數(shù)名字相同;

          (3)參數(shù)相同;

          (4)基類函數(shù)必須有virtual 關(guān)鍵字。

          c.“隱藏”是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:

          (1)如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時(shí),不論有無(wú)virtual關(guān)鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆,僅同名就可以)。

          (2)如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒(méi)有virtual 關(guān)鍵字。此時(shí),基類的函數(shù)被隱藏(注意別與覆蓋混淆)

          純虛函數(shù)

          class Disc_item : public Item_base 

          {
          ? ?public:
          ? ?double net_price(std::size_t) const = 0;
          };

          含有(或繼承)一個(gè)或多個(gè)純虛函數(shù)的類是抽象基類。除了作

          為抽象基類的派生類的對(duì)象的組成部分,甚至不能創(chuàng)建抽象類型Disc_item的對(duì)象。

          模板編程

          函數(shù)模板

          template <typename T> 
          int compare(const T &v1, const T &v2)
          {
          ? ?if (v1 < v2) return -1;
          ? ?if (v2 < v1) return 1;
          ? ?return 0;
          }

          使用compare(1, 2)

          類模板

          template <class Type> class Queue 

          {

          public:

          ? ?Queue (); // default constructor
          ? ?Type &front (); // return element from head of Queue
          ? ?const Type &front () const;
          ? ?void push (const Type &); // add element to back of Queue
          ? ?void pop(); // remove element from head of Queue
          ? ?bool empty() const; // true if no elements in the Queue
          ? ?private:
          ? ?// ...
          };

          使用Queue qi;


          操作符重載

          輸出操作符

          輸出操作符通常是非成員函數(shù),定義成類的友元

          friend ostream& operator<<(ostream& out, const Sales_item& s)
          {
          ? ?out << s.isbn << "\t" << s.units_sold << "\t"
          ? ?<< s.revenue << "\t" << s.avg_price();
          ? ?return out;
          }

          算術(shù)和關(guān)系操作

          算術(shù)和關(guān)系操作符定義為非成員函數(shù)

          為了與內(nèi)置操作符保持一致,加法返回一個(gè)右值,而不是一個(gè)引用。

          Sales_item operator+(const Sales_item& lhs, const Sales_item& rhs)

          {

          ? ?Sales_item ret(lhs); // copy lhs into a local object that we'll
          ? ?ret += rhs; // add in the contents of rhs
          ? ?return ret; // return ret by value
          }

          int operator<(const TableIndex2D& right) const;

          friend bool operator== (const UEContext& info1,const UEContext& info2) const
          {
          ? ?if(info1.ContextID != info2.ContextID) return false;
          ? ?return true;


          friend bool operator!= (const UEContext& info1,const UEContext& info2) const
          {
          return !(info1 == info2);
          }

          復(fù)制控制

          包括,一個(gè)拷貝構(gòu)造函數(shù),一個(gè)賦值運(yùn)算符,一個(gè)析構(gòu)函數(shù),一對(duì)取址運(yùn)算符

          如果你這么寫:class Empty{};

          和你這么寫是一樣的:

          class Empty 
          {
          ? ?public:
          ? ?Empty(); ? ? ? ? ? ?// 缺省構(gòu)造函數(shù)
          ? ?Empty(const Empty& rhs); ? ?// 拷貝構(gòu)造函數(shù)
          ? ?~Empty(); ? ? ? ? ? ?// 析構(gòu)函數(shù) ---- 是否
          ? ? ? ? ? ? // 為虛函數(shù)看下文說(shuō)明
          ? ? Empty& operator=(const Empty& rhs); ?// 賦值運(yùn)算符
          ? ? Empty* operator&(); ? ? ? // 取址運(yùn)算符
          ? ? const Empty* operator&() const;
          };

          Empty(const Empty& rhs)
          {
          ? ?a = rhs.a
          }


          類賦值操作符必須是類的成員,以便編譯器可以知道是否需要合成一個(gè), 賦值必須返回對(duì) *this 的引用。

          一般而言,賦值操作符與復(fù)合賦值操作符應(yīng)返回操作符的引用

          Guti& Guti::operator=( const Guti& rhs )
          {
          ?mtmsi_m = rhs.mtmsi_m;
          ?mmeCode_m = rhs.mmeCode_m;
          ?mmeGid_m = rhs.mmeGid_m;
          ?plmnId_m = rhs.plmnId_m;
          ?return *this;
          };

          注意,檢查對(duì)自己賦值的情況
          c& c::operator=(const c& rhs)
          {
          // 檢查對(duì)自己賦值的情況
          if (this == &rhs) return *this;
          ...
          }

          構(gòu)造函數(shù)初始化式

          初始化const對(duì)象和引用對(duì)象的唯一機(jī)會(huì)。P389 C++ Primer 5th


          協(xié)議

          RTP/RTSP/RTCP

          RTP協(xié)議RFC1889和RFC3550 G711 PCMU

          HTTP

          new操作

          動(dòng)態(tài)分配數(shù)組int *pia = new int[10]; // array of 10 uninitialized ints

          釋放分配的數(shù)組 delete [] pia;

          new數(shù)組

          int *arr = new int[1024]
          delte [] a
          # 堆上new 對(duì)象
          class MyClass
          {
          ? ?MyClass(int a) {};
          ? ?int empty() {return 0;};
          };

          MyClass *p = new MyClass(1);
          delete p;

          # 棧上分配 對(duì)象
          MyClass test(1);

          放置式new

          區(qū)分以下幾種操作符號(hào):

          new operator-普通的new關(guān)鍵字

          operator new-僅僅申請(qǐng)內(nèi)存返回void*

          placement new-在指定內(nèi)存調(diào)用構(gòu)造函數(shù)初始化類

          new [] operator-如果是類對(duì)象,會(huì)在首部多申請(qǐng)4字節(jié)內(nèi)存用于保存對(duì)象個(gè)數(shù)

          深入探究 new 和 delete

          https://blog.csdn.net/codedoctor/article/details/76187567

          當(dāng)我們使用關(guān)鍵字new在堆上動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象A時(shí),比如 A* p = new A(),它實(shí)際上做了三件事:

          向堆上申請(qǐng)一塊內(nèi)存空間(做夠容納對(duì)象A大小的數(shù)據(jù))(operator new)

          調(diào)用構(gòu)造函數(shù) (調(diào)用A的構(gòu)造函數(shù)(如果A有的話))(placement new)

          返回正確的指針

          當(dāng)然,如果我們創(chuàng)建的是簡(jiǎn)單類型的變量,那么第二步會(huì)被省略。

          當(dāng)我們delete的時(shí)候也是如此,比如我們delete p 的時(shí)候,其行為如下:

          定位到指針p所指向的內(nèi)存空間,然后根據(jù)其類型,調(diào)用其自帶的析構(gòu)函數(shù)(內(nèi)置類型不用)

          然后釋放其內(nèi)存空間(將這塊內(nèi)存空間標(biāo)志為可用,然后還給操作系統(tǒng))

          將指針標(biāo)記為無(wú)效(指向NULL)

          https://blog.csdn.net/rain_qingtian/article/details/14225211



          void* p=::operator new (sizeof(Buffer)); ?//創(chuàng)建一塊內(nèi)存;冒號(hào)表示全局的new
          Buffer* bp= start_cast<Buffer*>(p); ?//指針進(jìn)行裝換
          Buffer* buf3=new(bp) Buffer(128); ? //把bp指針指向的內(nèi)存租借buf3,
          buf3->put('c');
          buf3->~Buffer(); ?//這里析構(gòu)函數(shù)要顯示調(diào)用
          ::operator delete(p);

          放置new構(gòu)造對(duì)象數(shù)組

          在棧上分配類內(nèi)存:https://www.cnblogs.com/weekbo/p/8533368.html

          new與malloc區(qū)別

          b. new和malloc最大區(qū)別: new會(huì)調(diào)用類的構(gòu)造函數(shù),malloc不會(huì);

          c. delete和free同理;new/delete是運(yùn)算符,malloc/free函數(shù)。所以new/delete效率應(yīng)該會(huì)高點(diǎn)。

          Linux IPC機(jī)制匯總

          管道

           #include 

          無(wú)名管道: int pipe(int pipedes[2])

          有名管道:int mkfifo(const char *pathname, mode_t mode)


          消息隊(duì)列

          #include 

          int msgget(key_t key, int msgflg) //創(chuàng)建

          int msgctl(int msqid, int cmd, struct msqid_ds *buf) //設(shè)置/獲取消息隊(duì)列的屬性值

          int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) //發(fā)送消息到消息隊(duì)列(添加到尾端)

          ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) //接收消息


          共享內(nèi)存

          #include 

          int shmget(key_t key, size_t size, int shmflg) //創(chuàng)建一個(gè)共享內(nèi)存空間

          int shmctl(int shmid, int cmd, struct shmid_ds *buf) //對(duì)共享內(nèi)存進(jìn)程操作,包括:讀取/設(shè)置狀態(tài),刪除操作

          void *shmat(int shmid, const void *shmaddr, int shmflg) //將共享內(nèi)存空間掛載到進(jìn)程中

          int shmdt(const void *shmaddr) //將進(jìn)程與共享內(nèi)存空間分離 **(****只是與共享內(nèi)存不再有聯(lián)系,并沒(méi)有刪除共享內(nèi)存****)**


          信號(hào)

          #include


          手動(dòng)實(shí)現(xiàn)strcpy

          char *strcpy(char *strDest, const char *strSrc)
          {
          ? ?if ( strDest == NULL || strSrc == NULL)
          ? ?return NULL ;
          ? ?if ( strDest == strSrc)
          ? ?return strDest ;
          ? ?char *tempptr = strDest ;
          ? ?while( (*strDest++ = *strSrc++) != /0)
          ? ?return tempptr ;
          }


          C++對(duì)象內(nèi)存布局

          這部分詳細(xì)內(nèi)容可以參考《深度探索C++對(duì)象模型》

          虛函數(shù)多態(tài)機(jī)制

          通過(guò)虛表指針訪問(wèn)虛成員函數(shù),對(duì)普通成員函數(shù)的訪問(wèn)區(qū)別于虛成員函數(shù)。具體如下:

          virtual member function虛成員函數(shù)normalize()的調(diào)用實(shí)際上轉(zhuǎn)換成:

          (*ptr->vpter[1])(ptr)

          函數(shù)指針也有差別,下面第一個(gè)是普通函數(shù)指針或者static member function。第二個(gè)是non-static member function成員函數(shù)指針。

          不同繼承層次的對(duì)象內(nèi)存布局

          單一繼承

          多重繼承


          瀏覽 68
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大鸡吧内射网站 | 青草福利 | 夜噜噜久久国产欧美日韩精品 | 亚洲v网站在线观看 | 真人一级黄色片 |