C++面向?qū)ο笾惡蛯?duì)象那些你不知道的細(xì)節(jié)原理詳解
一、類和對(duì)象、this指針
OOP語言的四大特征是什么?
- 抽象
- 封裝、隱藏
- 繼承
- 多態(tài)
類體內(nèi)實(shí)現(xiàn)的方法會(huì)自動(dòng)處理為inline函數(shù)。
類對(duì)象的內(nèi)存大小之和成員變量有關(guān)
類在內(nèi)存上需要對(duì)齊,是為了減輕cup在內(nèi)存上的io次數(shù)
查看類對(duì)象的大小的指令:cl className.cpp /d1reportSingleClassLayout類名
一個(gè)類可以定義無數(shù)個(gè)對(duì)象,每個(gè)對(duì)象都有自己的成員變量,但是他們共享一套成員方法。
有一個(gè)問題:Q1:類中的成員方法是怎么知道要處理哪個(gè)對(duì)象的信息的?
A1:在調(diào)用成員方法的時(shí)候會(huì)在參數(shù)列表里隱式的給定對(duì)象內(nèi)存的地址。如下所示:
類的成員方法一經(jīng)編譯,所有方法參數(shù)都會(huì)加一個(gè)this指針,接收調(diào)用該方法的對(duì)象的地址,即下圖中的CGoods *this
二、掌握構(gòu)造函數(shù)和析構(gòu)函數(shù)
定義一個(gè)SeqStack類:
class SeqStack { public: SeqStack(int size = 10) :_top(-1), _size(size) { _pstack = new int[size]; } ~SeqStack() { cout << this << "~SeqStack()" << endl; delete[] _pstack; _pstack = nullptr; } void push(int val) { if (full()) { resize(); } _pstack[++_top] = val; } void pop() { if (empty()) { return; } --_top; } int top() { return _pstack[_top]; } bool empty() { return _top == -1; } bool full() { return _top == _size-1; } private: int* _pstack; int _top; int _size; void resize() { int* ptmp = new int[_size * 2]; for (int i = 0; i < _size; i++) { ptmp[i] = _pstack[i]; } delete[] _pstack; _pstack = ptmp; _size *= 2; } }; /** 運(yùn)行過程 */ int main() { SeqStack sq1; for (int i = 0; i < 15; i++) { sq1.push(rand() % 100); } while (!sq1.empty()) { cout << sq1.top() << " "; sq1.pop(); } return 0; }
三、掌握對(duì)象的深拷貝和淺拷貝
.data段的對(duì)象是程序啟動(dòng)的時(shí)候構(gòu)造的,程序結(jié)束的時(shí)候析構(gòu)的
heap堆上對(duì)象是new的時(shí)候構(gòu)造的,delete的時(shí)候析構(gòu)的
stack棧上的對(duì)象是在調(diào)用函數(shù)的時(shí)候構(gòu)造的,執(zhí)行完函數(shù)時(shí)析構(gòu)的
如果對(duì)象占用外部資源,淺拷貝就會(huì)出現(xiàn)問題:會(huì)導(dǎo)致一個(gè)對(duì)象指向的內(nèi)存釋放,從而造成另一個(gè)對(duì)象中的指針成為野指針。所以就要對(duì)這樣的對(duì)象進(jìn)行深拷貝,在新的對(duì)象中重新開辟一塊空間,使兩者互不干涉。
注意:在面向?qū)ο笾校苊馐褂胢emcpy進(jìn)行拷貝,因?yàn)閷?duì)象的內(nèi)存占用不確定,會(huì)因?yàn)閷?duì)象中保存指針而造成淺拷貝。需要拷貝的時(shí)候只能用for循環(huán)逐一拷貝。
深拷貝:
SeqStack& operator=(const SeqStack& src) { cout << "operator=" << endl; //防止自賦值 if (this == &src) { return *this; } delete[] _pstack;//需要釋放掉自身占用的外部資源 _pstack = new int[src._size]; for (int i = 0; i <= src._top; i++) { _pstack[i] = src._pstack[i]; } _top = src._top; _size = src._size; return *this; } SeqStack(const SeqStack& src) { cout << this << "SeqStack(const SeqStack& src)" << endl; _pstack = new int[src._size]; for (int i = 0; i <= src._top; i++) { _pstack[i] = src._pstack[i]; } _top = src._top; _size = src._size; }
四、類和對(duì)象應(yīng)用實(shí)踐
類Queue:
#pragma once class CirQueue { public: CirQueue(int size = 10) { _pQue = new int[size]; _front = _rear = 0; _size = size; } CirQueue(const CirQueue& src) { _size = src._size; _front = src._front; _rear = src._rear; _pQue = new int[_size]; for (int i = _front; i != _rear; i = (i + 1) % _size) { _pQue[i] = src._pQue[i]; } } ~CirQueue() { delete[] _pQue; _pQue = nullptr; } CirQueue& operator=(const CirQueue& src) { if (this == &src) { return *this; } delete[] _pQue;//需要釋放掉自身占用的外部資源 _size = src._size; _front = src._front; _rear = src._rear; _pQue = new int[_size]; for (int i = _front; i != _rear; i = (i + 1) % _size) { _pQue[i++] = src._pQue[i]; } return *this; } void push(int val) { if (full()) { resize(); } _pQue[_rear] = val; _rear = (_rear + 1) % _size; } void pop() { if (empty()) { return; } _front = (_front + 1) % _size; } int front() { return _pQue[_front]; } bool full() { return (_rear + 1) % _size == _front; } bool empty () { return _front == _rear; } private: int* _pQue; int _front; int _rear; int _size; void resize() { int* ptmp = new int[_size * 2]; int index = 0; for (int i = _front; i != _rear; i=(i+1)%_size) { ptmp[index++] = _pQue[i]; } delete[] _pQue; _pQue = ptmp; _front = 0; _rear = index; _size *= 2; } };
類String:
#pragma once #include <algorithm> class String { public: String(const char* str = nullptr) { if (str != nullptr) { _pChar = new char[strlen(str) + 1]; strcpy(_pChar, str); } else { _pChar = new char[1]; *_pChar = '\0'; } } String(const String& str) { _pChar = new char[strlen(str._pChar)+1]; strcpy(_pChar, str._pChar); } ~String() { delete[] _pChar; _pChar = nullptr; } String& operator=(const String& str) { if (this == &str) { return *this; } delete[] _pChar;//需要釋放掉自身占用的外部資源 _pChar = new char[strlen(str._pChar) + 1]; strcpy(_pChar, str._pChar); return *this; } private: char* _pChar; };
五、掌握構(gòu)造函數(shù)的初始化列表
初始化列表和寫在構(gòu)造體里有什么區(qū)別:
初始化列表會(huì)直接定義并且賦值;放在構(gòu)造體里會(huì)先執(zhí)行定義操作,在對(duì)定義好的對(duì)象賦值。
對(duì)象變量是按照定義的順序賦值的,與構(gòu)造函數(shù)中初始化列表的順序無關(guān)。上圖中的ma是0xCCCCCCCC,mb是10,ma未賦值。
六、掌握類的各種成員方法及其區(qū)別
普通成員方法和常成員方法,是可以重載的,常成員方法可以在對(duì)象聲明為const的時(shí)候調(diào)用。
對(duì)象聲明為const的時(shí)候,調(diào)用成員方法是通過const對(duì)象的指針調(diào)用的,而普通的成員方法默認(rèn)生成的是普通的指針對(duì)象,不能直接賦值。
只要是只讀操作的成員方法,一律實(shí)現(xiàn)成const常成員方法
三種成員方法:
七、指向類成員的指針
class Test { public: void func() { cout << "call Test::func" << endl; } static void static_func() { cout << "call Test::static_func" << endl; } int ma; static int mb; }; int Test::mb=0; int main() { Test t1; Test *t2 = new Test();//在堆上生成對(duì)象,并用指針指向 //使用指針調(diào)用類成員方法(前面要加類的作用域Test::) void (Test:: * pfunc)() = &Test::func; (t1.*pfunc)(); (t2->*pfunc)(); //定義指向static的類成員方法 void(*pfunc1)() = &Test::static_func; (*pfunc1)(); //使用指針指向類成員變量,前面要加類的作用域Test:: int Test::* p = &Test::ma; t1.*p = 20; cout << t1.*p << endl; t2->*p = 30; cout << t2->*p << endl; int* p1 = &Test::mb; *p1 = 40; cout << *p1 << endl; delete t2; return 0; }
輸出為:
總結(jié)
到此這篇關(guān)于C++面向?qū)ο笾惡蛯?duì)象那些你不知道的細(xì)節(jié)原理的文章就介紹到這了,更多相關(guān)C++類和對(duì)象的原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
簡(jiǎn)單了解設(shè)計(jì)模式中的裝飾者模式及C++版代碼實(shí)現(xiàn)
這篇文章主要介紹了簡(jiǎn)單了解設(shè)計(jì)模式中的裝飾者模式及C++版代碼實(shí)現(xiàn),ConcreteComponent的引用(指針)也可以達(dá)到修飾的功能,需要的朋友可以參考下2016-03-03VSCode下.json文件的編寫之(1) linux/g++ (2).json中參數(shù)與預(yù)定義變量的意義解釋
這篇文章主要介紹了VSCode下.json文件的編寫之(1) linux/g++ (2).json中參數(shù)與預(yù)定義變量的意義解釋,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03C++實(shí)現(xiàn)LeetCode(125.驗(yàn)證回文字符串)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(驗(yàn)證回文字符串).本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07select函數(shù)實(shí)現(xiàn)高性能IO多路訪問的關(guān)鍵示例深入解析
這篇文章主要為大家介紹了select函數(shù)實(shí)現(xiàn)高性能IO多路訪問的關(guān)鍵示例深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09C語言實(shí)現(xiàn)共享單車管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)共享單車管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08