1. 程式人生 > >5.2-day02-C++/內聯/動態記憶體分配/引用/顯示型別轉換

5.2-day02-C++/內聯/動態記憶體分配/引用/顯示型別轉換

九、 3.內聯 1)編譯器用函式的二進位制程式碼替換函式呼叫語句,減少函式呼叫的時間開銷。這種優化策略成為內聯。 2)頻繁呼叫的簡單函式適合內聯,而稀少呼叫的複雜函式不適合內聯。 3)遞迴函式無法內聯。 4)通過inline關鍵字,可以建議編譯對指定函式進行內聯,但是僅僅是建議而已。 inline void foo (int x, int y){...} 十、C++的動態記憶體分配 malloc/calloc/realloc/free 1.new/delete:對單個變數進行記憶體分配/釋放 2.new[ ]/delete[ ]:對陣列進行記憶體分配/釋放 十一、引用 1.引用即別名。 int a = 20; int& b = a; // int* b = &a;     引用的本質就是指標 b = 10; // *b = 10; cout << a << endl; // 10  2.引用必須初始化。 int a; int* p; a = 20; p = &a; int& b; // ERROR ! int& b = a; // OK 3.引用一旦初始化就不能再引用其它變數。 int a = 20, c = 30; int& b = a; b = c; // c => b/a 4.引用的應用場景 1)引用型引數 a.修改實參 b.避免拷貝,通過加const可以防止在函式中意外地修改實參的值,同時還可以接受擁有常屬性的實參。 2)引用型返回值 int b = 10; int a = func (b); func (b) = a; 從一個函式中返回引用往往是為了將該函式的返回值作為左值使用。但是,一定要保證函式所返回的引用的目標在該函式返回以後依然有定義,否則將導致不確定的後果。 不要返回區域性變數的引用,可以返回全域性、靜態、成員變數的引用,也可以返回引用型形參變數本身。 5.引用和指標 1)引用的本質就是指標,很多場合下引用和指標可以互換。 2)在C++層面上引用和指標存在以下不同: A.指標式實體變數,但是引用不是實體變數。 int& a = b; sizeof (a); // 4 double& d = f; sizeof (d); // 8 B.指標可以不初始化,但是引用必須初始化。 C.指標的目標可以修改,但是引用的目標的不能修改。 D.可以定義指標的指標,但是不能定義引用的指標。 int a; int* p = &a; int** pp = &p; // OK int& r = a; int&* pr = &r; // ERROR E.可以定義指標的引用,但是不能定義引用的引用。 int a; int* p = &a; int*& q = p; // OK int& r = a; int&& s = r; // ERROR F.可以定義指標的陣列,但是不能定義引用的陣列。 int a, b, c; int* parr[] = {&a, &b, &c}; // OK int& rarr[] = {a, b, c}; // ERROR 可以定義陣列的引用。 int arr[] = {1, 2, 3}; int (&arr_ref)[3] = arr; // OK 十二、顯示型別轉換運算子 C:目標型別變數 = (目標型別)源型別變數; 1.靜態型別轉換 static_cast<目標型別> (源型別變數) 如果在目標型別和源型別之間某一個方向上可以做隱式型別轉換,那麼在兩個方向上都可以做靜態型別轉換。反之如果在兩個方向上都不能做隱式型別轉換,那麼在任意一個方向上也不能做靜態型別轉換。 int* p1 = ...; void* p2 = p1; p1 = static_cast<int*> (p2); char c; int i = c; 如果存在從源型別到目標型別的自定義轉換規則,那麼也可以使用靜態型別轉換。 2.動態型別轉換 dynamic_cast<目標型別> (源型別變數) 用在具有多型性的父子類指標或引用之間。 3.常型別轉換 const_cast<目標型別> (源型別變數) 給一個擁有const屬性的指標或引用去常 const int a = 100; const int* p1 = &a; *p1 = 200; // ERROR int* p2 = const_cast<int*> (p1); *p2 = 200; // OK 4.從解釋型別轉換 reinterpret_cast<目標型別> (源型別變數); 在不同型別的指標或引用之間做型別轉換,以及在指標和整型之間做型別轉換。 5.目標型別變數 = 目標型別(源型別變數); int a = int (3.14); 十三、C++之父的建議 1.少用巨集,多用const、enum和inline #define PAI 3.141519 const double PAI = 3.14159; #define ERROR_FILE -1 #define ERROR_MEM  -2 enum {   ERROR_FILE = -1,   ERROR_MEM = -2 }; #define max(a,b) ((a)>(b)?(a):(b)) inline int double max (double a, double b) {   return a > b ? a : b; } 2.變數隨用隨宣告同時初始化。 3.少用malloc/free,多用new/delete。 4.少用C風格的強制型別轉換,多用型別轉換運算子。 5.少用C風格的字串,多用string。 6.樹立面向物件的程式設計思想。 ++C 第二課  類和物件 一、什麼是物件 1.萬物皆物件 2.程式就是一組物件,物件之間通過訊息交換資訊 3.類就是對物件的描述和抽象,物件就是類的具體化和例項化 二、通過類描述物件 屬性:姓名、年齡、學號 行為:吃飯、睡覺、學習 類就是從屬性和行為兩個方面對物件進行抽象。 三、面向物件程式設計(OOP) 現實世界                 虛擬世界 物件    -> 抽象 -> 類 -> 物件 1.至少掌握一種OOP程式語言 2.精通一種面向物件的元語言—UML 3.研究設計模式,GOF 四、類的基本語法 1.類的定義 class 類名 { }; 如 class Student { }; 2.成員變數——屬性 class 類名 {   型別 成員變數名; }; 如 class Student {   string m_name;   int    m_age; }; 3.成員函式——行為 class 類名 {   返回型別 成員函式名 (形參表) {     函式體;   } }; 如 class Student {   string m_name;   int    m_age;   void eat (const string& food) {     ...   } }; 4.訪問控制屬性 1)公有成員:public,誰都可以訪問。 2)私有成員:private,只有自己可以訪問。 3)保護成員:protected,只有自己和自己的子類可以訪問。 4)類的成員預設訪控屬性為私有,而結構的成員預設訪控屬性為公有。
1.c
    
  1. #include
    <iostream>
  2. using namespace std;
  3. int main (void) {
  4. cout << "Hello, World !" << endl;
  5. return 0;
  6. }
 
1.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. int main (void) {
  4. auto i
    = 10;
  5. auto f = 3.14;
  6. cout << i << ' ' << f << endl;
  7. return 0;
  8. }
 用2011編譯器去編譯;  g++ 11.cpp -std=c++0x
const.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. int main (
    void) {
  4. const volatile int a = 100;
  5. // a = 200;
  6. const volatile int* p1 = &a;
  7. // *p1 = 200;
  8. int* p2 = const_cast<int*> (p1);
  9. *p2 = 200;
  10. cout << *p2 << endl; // 200
  11. cout << a << endl; // 200
  12. // cout << 100 << endl;
  13. return 0;
  14. }
  強制型別轉換:放棄一切安全機制;   目標型別變數=(目標型別) 源型別變數;  C++編譯器:靜態編譯器;  靜態:static_cast  動態:dynamic_cast
【給一個擁有const屬性的指標或引用去常,去掉常屬性】   const 只讀屬性     const int a = 100;   //常量優化 不管a是多少,a都為100,打出a的字面值,用100去優化;
const volatile int a = 100;  別做優化,會用a的值輸出;  用volatile保證不做暫存器優化,常量優化的值; 保證訪問的是記憶體中的值,而不是歷史值;  new返回的是陣列的首地址;

new.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. int main (void) {
  4. // int* pi = (int*)malloc (sizeof (int));
  5. // free (pi);
  6. int* pi = new int;
  7. *pi = 1000;
  8. cout << *pi << endl;
  9. delete pi;
  10. pi = NULL;
  11. /*
  12. *pi = 2000;
  13. cout << *pi << endl;
  14. */
  15. pi = new int[10];
  16. for (size_t i = 0; i < 10; ++i)
  17. pi[i] = i;
  18. for (size_t i = 0; i < 10; ++i)
  19. cout << pi[i] << ' ';
  20. cout << endl;
  21. delete[] pi;
  22. pi = NULL;
  23. pi = new int (1234);
  24. cout << *pi << endl;
  25. delete pi;
  26. pi = NULL;
  27. char buf[4] = {0x12,0x34,0x56,0x78};
  28. pi = new (buf) int;
  29. cout << hex << *pi << endl;
  30. // delete pi;
  31. cout << (void*)pi << ' ' << (void*)buf << endl;
  32. int (*p)[4] = new int[3][4];
  33. delete[] p;
  34. int (*q)[4][5] = new int[3][4][5];
  35. delete[] q;
  36. return 0;
  37. }
 new/delete:對單個變數進行記憶體分配/釋放;  new[]/delete[]:對陣列進行記憶體分配/釋放;   new  int[3][4]  返回的是一個二維陣列第一個元素的地址;
三維陣列:二維陣列的陣列 int (*p) [4] = new   int [3][4]; 用二維陣列的指標去接受三維陣列;   
動態記憶體分配: string自動維護記憶體,無記憶體限制; “\0”,且自動新增 ‘\0’
對單個變數:   對陣列:  malloc在堆裡釋放記憶體,只malloc不free, 稱為記憶體的洩露;    int  *pi = new int;   new:對單個變數進行記憶體的分配;   野指標:存著一個地址,但裡面標識的記憶體已經被釋放;      以陣列方式new的,要用delete[] 刪掉;   pi = new int [10];  ......delete[] pi;     delete    pi;   區域性釋放   delete[ ] pi;  全部釋放     pi = new int (1234);    new的同時賦初值; 棧記憶體不能delete;  pi = new (buf)int;        以buf為首的,int大小區域;
reinter.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. int main (void) {
  4. int i = 0x12345678;
  5. char* p = reinterpret_cast<char*> (&i);
  6. for (size_t i = 0; i < 4; ++i)
  7. cout << hex << (int)p[i] << ' ';
  8. cout << endl;
  9. float* q = reinterpret_cast<float*> (&i);
  10. cout << *q << endl;
  11. void* v = reinterpret_cast<void*> (i);
  12. cout << v << endl;
  13. return 0;
  14. }
 reinterpret_cast <> (  ) //重解釋型別轉換-同一個記憶體,從不同角度(不同指標型別去看),對風馬牛不相及的指標進行轉化;


retref.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. int g_data = 100;
  4. int& foo (void) {
  5. return g_data;
  6. }
  7. int& bar (void) {
  8. int a = 100;
  9. return a;
  10. }
  11. int& fun (void) {
  12. int b = 200;
  13. return b;
  14. }

  15. int& hum (int& a) {
  16. return a;
  17. }
  18. int main (void) {
  19. int data = foo ();
  20. cout << data << endl; // 100
  21. foo () = 200;
  22. cout << g_data << endl;
  23. foo () += 100;
  24. ++foo ();
  25. cout << g_data << endl; // 301
  26. int& a = bar ();
  27. fun ();
  28. cout << a << endl; // 200
  29. return 0;
  30. }
          int b = 10;   int a = func(b);     返回右值;   func(b) = a;          返回左值;     foo ( ) = 200;    //200賦給臨時變數;
  int & foo (void) {    return g_data;    }    // 200賦給g_data了,此時賦的是別名int & foo (void);
static.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. int main (void) {
  4. int* p1 = NULL;
  5. void* p2 = p1;
  6. p1 = static_cast<int*> (p2);
  7. return 0;
  8. }
指標p2進行靜態型別轉換:  p1 = static_cast<int*> (p2);  
  string.cpp
    
  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. using namespace std;
  5. int main (void) {
  6. string s1 ("hello");
  7. string s2 = "world";
  8. (s1 += " ") += s2;
  9. cout << s1 << endl;
  10. string s3 = s1;
  11. cout << s3 << endl;
  12. cout << (s1 == s3) << endl;
  13. s3[0] = 'H';
  14. cout << s3 << endl;
  15. cout << (s1 > s3) << endl;
  16. cout << s1.length () << endl;
  17. cout << (s1 == s3) << endl;
  18. cout << (strcasecmp (s1.c_str (),         s3.c_str ()) == 0) << endl; cout << sizeof (s1) << endl;
  19. FILE* fp = fopen ("string.txt", "w");
  20. // fwrite (&s3, sizeof (s3), 1, fp);
  21. fwrite (s3.c_str (), sizeof (char),
  22. s3.length (), fp);
  23. fclose (fp);
  24. return 0;
  25. }
 
  1. cout << (strcasecmp (s1.c_str (),
  2. s3.c_str ()) == 0) << endl;
 不區分大小寫進行比較,因為要求用char型別,所以用s1.c_str()和s3.c_str()

student.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. class Student {
  4. private:
  5. string m_name;
  6. int m_age;
  7. public:
  8. void eat (const string& food) {
  9. cout << m_age << "歲的" << m_name
  10. << "同學正在吃" << food << "。" << endl;
  11. }
  12. void setName (const string& name) {
  13. if (name == "2")
  14. cout << "你才" << name << "!" << endl;
  15. else
  16. m_name = name;
  17. }
  18. void setAge (int age) {
  19. if (age < 0)
  20. cout << "無效的年齡!" << endl;
  21. else
  22. m_age = age;
  23. }
  24. };
  25. int main (void) {
  26. Student student;
  27. student.setName ("2");
  28. student.setAge (-100);
  29. student.setName ("張飛");
  30. student.setAge (20);
  31. student.eat ("包子");
  32. return 0;
  33. }



swap.cpp
    
  1. #include <iostream>
  2. using namespace std;
  3. void swap1 (int a, int b) {
  4. int c = a;
  5. a = b;
  6. b = c;
  7. }
  8. void swap2 (int* a, int* b) {
  9. int c = *a;
  10. *a = *b;
  11. *b = c;
  12. }
  13. void swap3 (int& a, int& b) {
  14. int c = a;
  15. a = b;
  16. b = c;
  17. }
  18. void swap4 (const char* x, const char* y) {
  19. const char* z = x;
  20. x = y;
  21. y = z;
  22. }
  23. void swap5 (const char** x, const char** y) {
  24. const char* z = *x;
  25. *x = *y;
  26. *y = z;
  27. }
  28. void swap6 (const char*& x, const char*& y) {
  29. const char* z = x;
  30. x = y;
  31. y = z;
  32. }
  33. struct Student {
  34. char name[1024];
  35. int age;
  36. };
  37. void print (const struct Student& s) {
  38. cout << s.name << "," << s.age << endl;
  39. // s.age = -1;
  40. }
  41. void foo (const int& x)
  42. cout << x << endl;
  43. }
  44. int main (void) {
  45. int a = 100, b = 200;
  46. // swap1 (a, b);
  47. // swap2 (&a, &b);
  48. swap3 (a, b);
  49. cout << a << ' ' << b << endl; // 200 100
  50. const char* x = "hello", *y = "world";
  51. // swap4 (x, y);
  52. // swap5 (&x, &y);
  53. swap6 (x, y);
  54. cout << x << ' ' << y << endl;
  55. Student s = {"張飛", 22};
  56. print (s);
  57. print (s);
  58. foo (100);
  59. return 0;
  60. }
 引用:  swap3 (a, b);     -> void swap3 (int& a, int& b)  {......}
指標:
void swap5 (const char** x, const char** y) 要用二級指標,即,const char ** x 
引用型引數: void print ( const struct Student & s )
&符號避免拷貝的開銷;提高了效率;  避免拷貝,通過加const可以防止在函式中意外地修改實參的值,  同時還可以接受擁有常屬性的實參。









來自為知筆記(Wiz)