【2016/3】C++ 類與對象進階 運算符重載 new delete 模板 繼承

版權聲明:本文爲博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hsgwpj/article/details/50933777

類與對象:

const常量哪怕棧空間數據被改 被訪問時依然是使用存於符號表的數據

構造函數的形式:
拷貝構造 Test(Test &t){}
初始化構造 Test(int d): data(d){}

   Test t(10);
   t = 200;    
   //只要類型不同,會創建一箇中間的無名變量來賦值;
   //實際上是調用了構造函數中的 Test(200) 創建了一個對象,將對象賦值給t;
   //如果構造函數中使用explicit作爲修飾,不能隱式轉化時,會杜絕這種情況發生;
   //上一行的情況則必須 使用:   t = (Test) 200;

   Test t1 = t2;       //拷貝構造
   Test t1; t1 = t2;   //運算符重載賦值

拷貝構造: 形如 void fun(Test a);
如果函數的參數是以傳入對象的形式, 那麼傳入對象的時候會進行一次拷貝構造

     返回值是對象的時候: Test fun(int a)
                         {
                             Test new_one(a);
                             return new_one;
                         }
如果編譯器做了優化 可能會延長返回對象的生存週期 而不是重新拷貝構造一個無名對象來返回

*拷貝構造的時候要考慮淺拷貝和深拷貝的問題

         注意: 局部對象不能以引用形式返回,局部對象會被銷燬

*拷貝構造的參數最好使用const修飾 比如Test(const Test &t)(…)
因爲return的時候可能會檢測到拷貝構造函數,而return返回的對象具有常性,需要const屬性

賦值函數的編寫:
1.自身賦值問題
2.釋放原有內存的空間
3.開闢空間深拷貝賦值數據
4.返回自身對象
—- Tip:異常安全問題 在賦值期間發生異常 保證賦值兩者的數據安全

*類成員有指針的時候 考慮拷貝構造和析構還有運算符重載的安全性

vld.h: 檢測內存泄露的庫

Question: C++的類的初始的函數有六個 分別是什麼?
explicit關鍵字的用法?
如何把一個只有一個數據成員的對象直接給一個該數據的變量賦值?(Test t(200); int value = t;)

成員函數中用const修飾的方法:
void Test::fun()const;
實際上相當於
void Test::fun(const Test * const this);
本質上就是不能修改this所指的對象的值;
***tips: 常方法不能調用有可能改變對象的值的成員函數;

成員函數中的static修飾的方法:
static修飾的變量以及函數,被所有對象共享,沒有this指針;
***tips: 靜態方法不能調用成員函數,因爲它是被所有類對象共享的;

用friend關鍵字修飾的友元函數可以訪問私有成員;
— 常用來重載流運算符;

運算符重載:

   **不能使用的重載運算符:**
       三目運算符: ?:
       成員訪問符: . .*
       字長訪問符: sizeof
       作用域符:   ::
++運算符的重載:
    前置++: Test operator++();
    後置++: Test operator++(int);
        此處的int僅作爲標記使用;
流運算符重載:
   friend ostream& operator<<(ostream &out, const Test &t);
   {
       out << t.data;
       return out;
   }

作爲友元函數進行重載;

C++如何實現的重載:
   編譯器在彙編階段根據函數的參數通過自己的一套命名方式
   將函數進行一系列重命名,翻譯成另一個具有唯一性的名字(帶上函數的參數)

   當加入extern "C" 修飾函數的時候用C的模式彙編

空間分配(new && delete):

new 等同於 C 語言中的 (強制轉化 *)malloc(sizeof(類型));

   int *p   = new int(10);     //新建一個值爲10的整形
   int *p   = new int[10];     //新建一個有10個成員的整形數組

   int *p   = new Test;        //調用構造函數申請空間(如果要求有參數必須寫參數)

   int *p   = new Test[10];    //構造10個對象!
                               //Tips: 如果要直接構造,一定要有默認(帶參)的構造函數
   delete []p;                 //*** 通過delete刪除掉連續申請的對象空間 否則內存泄露
       //方括號只起到標記作用,標識是釋放一個數組空間

new的步驟:
1.申請空間;
2.調用構造函數在申請的空間內構造對象;

delete的步驟:
1.調用析構函數析構對象;
2.釋放空間;

模板:

   #include <typeinfo>
   template<typename Type>
   Max(Type a, Type b)
   {
       cout<<typeid(Type).name()<<endl;
       //打印出Type的類型
       return a>b ? a:b;
   }

實現是先通過一系列操作與函數模板, 製作出相應類型的模板函數
最後再用模板函數來實現函數功能

類的形式類似;

可以直接調用:
Max(1,2);
Max(‘A’, ‘X’);
或者顯式調用:
Max(1,2);
Max(‘A’, ‘X’);

Gdb調試:

1.g++ -o -g
2.gdb
3.list
4.b 加斷點
5.run

new && delete:

1.new operator -> 1)分配空間 2)構造函數
              (直接使用 new 關鍵字)
2.operator new -> 只分配空間
              (直接使用 operator new 關鍵字)

可以重載new操作符來影響其分配空間的操作

   void *operator new(size_t sz)
   {
       void *p = malloc(sz);
       return p;
   }

要求返回值void * 傳入參數 size_t

同時如果你重載了new操作符,就要求你重載delete操作符

   void operator delete(void *p)
   {
       free(p);
   }

*Tips:free 與 malloc對應
new 與 delete對應
operator new 與 operator delete 對應

同理 new[] 與 delete[] 也可以重載
實際上new[] 在申請空間的時候,
頭部會多出一部分cookie空間, 大小爲一個指針的大小
存儲着用戶的信息:起始位置,釋放多少個對象
此時纔可以以delete[]來釋放相應的空間

類裏面也可以重載new delete操作符,而且會被對象優先使用

如果是void*p = new Test(10);
那麼delete p的時候 不會調用類的析構函數;

3.placement new

通過malloc開闢空間之後
int p = (int )malloc(sizeof(int) * 10)
可以通過new(p)int(10)來對申請的空間進行賦值
這種語法稱之爲定位new

這樣的new也是可以重載的:

   void *operator new(size_t sz, void *data, int pos)
   {
       return (data + pos);
   }

則使用方法變爲

new(p, 3)int(200);

對p所指的第三個位置進行賦值200的操作

繼承和多態:

子類雖然公有繼承了基類的私有成員
但是依然不能在自己的方法中改變基類
正確的用法是在基類中設置相應的設置方法來設置基類的成員

父類的信息能否被子類調動?
   ***父類任意私有數據都不能被子類直接調用
   但是父類的公有方法與保護方法都可以被子類的方法調用
   只有公有方法可以被對象直接訪問
保護方法存在的意義:
   ***保護只在繼承的時候體現它的性質
   不想被外部的對象調用, 爲了給子類提供藉口而存在
   其他一切特點等同於私有

class C: D
默認是私有繼承 (class C: private D)

多繼承:
   多繼承的構造函數順序就是繼承列表從左往右
   同時先構造成員的類對象再構造自身類對象
   構造函數書寫方法:
   C(a, b, c): A(a), B(b), C(c){}
   子類要調用基類的構造方法

   二義性:
       父類有同名的變量
       那麼需要通過加入 父類:: 來避免二義性
虛繼承:
   可以避免繼承同一個基類產生變量的二義性
同名隱藏:
   如果子類和父類有同名的方法
   那麼父類的同名方法會完全被隱藏(哪怕是重載)
   但是可以通過使用::這個來直接調用父類方法

看書:
1.重載 2.覆蓋 3.隱藏

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章