C++面向對象編程思想

 

1、C語言和c++的函數重載(同名不一樣參),相互調用,對象(參數)傳遞與引用

1. 類外定義函數,可用類名::函數名進行編寫,在類內須要聲明該函數

Class stu{html

//成員java

//屬性ios

Private://沒有private就默認publicc++

Int age;數組

Char* name;框架

//方法engjiide

Public:函數

Void init();學習

}網站

 

Void stu::init(){ //stu::代表該函數爲類內部方法}

 

int main(){

stu s;

return 0;

}

2. 結構體成員按對齊分配大小,取決於最大的

例如:

Struct stu{

double a; //8位

int i; //加8位(本來只有4位)等於16位

char c; //因爲Int後4位沒有佔用,char直接佔用,16不改變

char c2; // 同上

}

sizeof(stu) = 16

3. 對象的建立,this指針指向調用的對象,對象的引用

javanew建立對象時的內存分配。

Stu s; //java中使用這語句時,定義標識符s,沒有實際空間,只有new才分配空間建立對象

Stu stu; //在棧中申請空間,不能有括號,在程序結束後自動執行析構函數銷燬對象

Stu stu1 = new Stu(); //在堆中申請空間

Stu *pstu = &stu1; //new建立類對象須要指針接收,一處初始化,多處使用

Stu *stu2 = new Stu();

delete pstu; //刪除對象new建立類對象使用完需delete銷燬

 

 

4. 類的定義與封裝

class Stu{

int age;

char* name;

 

public: //公有的方法

void init(int age, char* name){} //初始化方法

}

 

void Stu::init(int age, char* name){ //Stu::指明瞭該函數爲類內部方法

this->age = age;

this->name = name;

}

 

int main(int argc, char* argv[]){

Stu stu1;

 

stu1.init(19, "ye");

 

}

5.類方法(函數)構造,無返回值也無void,能夠無參數;constructordestructor

class Stu{

int age;

char* name;

 

public: //公有的

//實例函數,但不是構造函數

void init(int age, char* name){} //初始化對象屬性值的函數

/*構造函數必須同時知足下面三個條件:

一、函數名和類名相同

二、在函數名的前面沒有返回值類型的聲明,void也沒有

三、在函數中不能使用return語句返回一個值

4.構造函數在建立對象時自動執行,通常不能顯式地直接調用*/

Stu();//能夠無參數,用來初始化對象(默認被構造)

Stu(int age); //函數重載

Stu(int age=0, char* name);//默認參數

Stu(int* num);

}

析構函數:對象消亡時,自動被調用,用來釋放對象(或構造函數請求的)佔用的空間。

特色:
   (1) 名字與類名相同
   (2) 在前面須要加上"~"
   (3) 無參數,無返回值
   (4) 一個類最多隻有一個析構函數
   (5) 不顯示定義析構函數會調用缺省析構函數

class Test{

    int id;

public:

    Test(int i){

        id = i;

    }

    ~Test(){

        cout<<"ID: "<<id<<" destruction function is invoked!"<<endl;

    };

};

int main(){

    Test t0(0);                   //棧中分配   

    Test t1[3]{1,1,1};        //棧中分配,數組型對象

    Test *t2 = new Test(2);       //堆中分配

    delete t2;

    Test *t3 = new Test[3]{3,3,3};//堆中分配

    delete []t3;

    cout<<"------End of Main-------"<<endl;

    return 0;

}

 

copy construction,拷貝構造函數是一種特殊的構造函數,函數的名稱必須和類名稱一致,它必須的一個參數是本類型的一個引用變量。

 

在某些情況下,類內成員變量須要動態開闢堆內存,若是實行位拷貝,也就是把對象裏的值徹底複製給另外一個對象,如A=B。這時,若是B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。

深拷貝和淺拷貝能夠簡單理解爲:若是一個類擁有資源,當這個類的對象發生複製過程的時候,資源從新分配,這個過程就是深拷貝,反之,沒有從新分配資源,就是淺拷貝。

 

所謂淺拷貝,就是說編譯器提供的默認的拷貝構造函數和賦值運算符重載函數,僅僅是將對象a中各個數據成員的值拷貝給對象b中對應的數據成員(這裏假設ab爲同一個類的兩個對象,且用a拷貝出b或用a來給b賦值),而不作其它任何事。

當用一個已初始化過了的自定義類類型對象去初始化另外一個新構造的對象的時候,拷貝構造函數就會被自動調用。也就是說,當類的對象須要拷貝時,拷貝構造函數將會被調用。如下狀況都會調用拷貝構造函數:

<![if !supportLists]>l <![endif]>一個對象以值傳遞的方式傳入函數體 

<![if !supportLists]>l <![endif]>一個對象以值傳遞的方式從函數返回 

<![if !supportLists]>l <![endif]>一個對象須要經過另一個對象進行初始化。

<![if !supportLists]>l <![endif]>

 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5 class CExample
 6 
 7 {
 8 
 9 private:
10 
11     int a;
12 
13 public:
14 
15     //構造函數
16 
17     CExample(int b)
18 
19     {
20 
21         a=b;
22 
23         printf("constructor is called\n");
24 
25     }
26 
27     //自定義的拷貝構造函數,深拷貝
28 
29     CExample(const CExample & c)
30 
31     {
32 
33         a=c.a;
34 
35         printf("copy constructor is called\n");
36 
37     }
38 
39     //析構函數
40 
41     ~CExample()
42 
43     {
44 
45         cout<<"destructor is called\n";
46 
47     }
48 
49     void Show()
50 
51     {
52 
53         cout<<a<<endl;
54 
55     }
56 
57 };
58 
59  
60 
61 int main()
62 
63 {
64 
65     CExample A(100);
66 
67     CExample B=A;
68 
69     B.Show(); 
70 
71     return 0;
72 
73 }
74 
75  

 

 

2、變量與常量基本使用

6.static local variable使用

 1 /* static local variable
 2 
 3 靜態局部變量,不會分配在傳統的棧區,不會被釋放,效果至關於全局變量,但不會被函數外的所訪問
 4 
 5 僅在聲明它的文件中可見,同一工程的其它文件中不可見,可解決不一樣文件的變量/函數重名問題; 
 6 
 7 */
 8 
 9 int global; //全局變量在程序開始時(main以前)被建立,結束時釋放
10 
11  
12 
13 void fun(){
14 
15 static int i = 0; //在第一次執行時被建立,程序徹底結束後才釋放,並非函數退出釋放當且僅當第一次執行才初始化,以後的值至關於保留上次結果
16 
17 int j;
18 
19 int k;
20 
21 cout << i++ << endl;
22 
23 cout << &j << &k << &i << endl; //地址與j,k不在同一區域
24 
25 }
26 
27  
28 
29 class Test{
30 
31     int id;
32 
33 static int j; //類中對象所共有的
34 
35 public:
36 
37     Test(int i){
38 
39         id = i;
40 
41     }
42 
43     ~Test(){
44 
45         cout<<"ID: "<<id<<" destruction function is invoked!"<<endl;
46 
47     };
48 
49 static void a_func(); //靜態函數,能夠直接經過類調用函數
50 
51 };
52 
53  
54 
55 /*相似全局變量的方式對類內的局部變量定義,共享使用,至關於對全部對象初始化,不管這個類的對象定義了多少個,靜態數據成員在程序中也只有一份拷貝,由該類型的全部對象共享訪問。
56 
57 */
58 
59 //即靜態數據成員是該類的全部對象所共有的
60 
61 int Test::j = 10;
62 
63  
64 
65 int main(){
66 
67 for(int i = 0; i <= 10; i++)
68 
69 fun(); //i輸出1,2,3,4……
70 
71 Test::a_func(); //static型可直接調用,而不須要建立對象
72 
73 return 0;
74 
75 }
76 
77  

 

7.const 常量的使用

 1 /* const
 2 
 3 常量
 4 
 5 */
 6 
 7 #include<iostream>
 8 
 9 #include<cstring>
10 
11 using namespace std; //命名空間,類做用域
12 
13  
14 
15 const int i = 0; //常量不容許賦值,因此必須初始化,其做用域不會被改變
16 
17 const int v[] = {1,2,3}; 
18 
19  
20 
21 void f1(const int i){
22 
23 i++; // Illegal compile 參數傳遞const值不能被改變
24 
25 }
26 
27  
28 
29 const int* const w(){ //返回值要求這個指針以及這個指針所指向的對象均爲常量
30 
31 static int i; //靜態的局部變量,有效
32 
33 return &i;
34 
35 }
36 
37  
38 
39 const int g(){}; // 返回const值,約定了函數框架裏的原變量不會被修改
40 
41  
42 
43 int main(){
44 
45 strcpy(s1, s2); // char * strcpy(char *s1, const char *s2);
46 
47 //含有const爲輸入,無則爲輸出,且 s2不會被修改,稱做指針參數
48 
49 return 0;
50 
51 }
52 
53  
54 
55 /* const常量,保證只有一個對象,在全局做用域裏聲明的const變量是定義該對象的文件的局部變量,此變量只存在於那個文件中,不能被其它文件訪問。
56 
57 */
58 
59 class Schedule() {
60 
61 Schedule();
62 
63 static Schedule* self;
64 
65 public:
66 
67 static Schedule* get_instance();
68 
69 }
70 
71  
72 
73 Schedule* Schedule::self = NULL;
74 
75  
76 
77 int main(){
78 
79 Schedule* s = Schedule::get_instance();
80 
81 return 0;
82 
83 }
84 
85  
86 
87 /* const常量在類中使用,const引用是指向const對象的引用,
88 
89 */
 1 #include<stdlib.h>
 2 
 3  
 4 
 5 class Fred() {
 6 
 7 const int size; // 不能直接初始化,須要在構造函數裏
 8 
 9 public:
10 
11 Fred(int sz);
12 
13 void print();
14 
15 }
16 
17  
18 
19 Fred::Fred(int sz) : size(sz) {} //在構造函數裏,const一定已經初始化了
20 
21 void Fred::print() {
22 
23 cout << size << endl;
24 
25 }
26 
27  
28 
29 int main(){
30 
31 Fred a(1), b(2), c(3);
32 
33 a.print(), b.print(), c.print();
34 
35 return 0;
36 
37 }
38 
39  

8.運算符重載

 

博客:大整數運算符重載:http://www.javashuo.com/article/p-akiippup-bn.html

賦值運算符重載函數不能被繼承

 

  1 #include<cstdio>
  2 
  3 #include<cstring>
  4 
  5 #include<vector>
  6 
  7 #include<algorithm>
  8 
  9 #include<iostream>
 10 
 11 using namespace std;
 12 
 13  
 14 
 15 struct BigInteger {
 16 
 17     static const int BASE = 100000000;
 18 
 19     static const int WIDTH = 8;
 20 
 21     vector<int> s;
 22 
 23  
 24 
 25     BigInteger(long long num = 0) { *this = num; } // 構造函數
 26 
 27     BigInteger operator = (long long num) { // 賦值運算符
 28 
 29         s.clear();
 30 
 31         do {
 32 
 33             s.push_back(num % BASE);
 34 
 35             num /= BASE;
 36 
 37         } while (num > 0);
 38 
 39         return *this;
 40 
 41     }
 42 
 43     BigInteger operator = (const string& str) { // 賦值運算符
 44 
 45         s.clear();
 46 
 47         int x, len = (str.length() - 1) / WIDTH + 1;
 48 
 49         for (int i = 0; i < len; i++) {
 50 
 51             int end = str.length() - i*WIDTH;
 52 
 53             int start = max(0, end - WIDTH);
 54 
 55             sscanf(str.substr(start, end-start).c_str(), "%d", &x);
 56 
 57             s.push_back(x);
 58 
 59         }
 60 
 61         return *this;
 62 
 63     }
 64 
 65     BigInteger operator + (const BigInteger& b) const {
 66 
 67         BigInteger c;
 68 
 69         c.s.clear();
 70 
 71         for (int i = 0, g = 0; ; i++) {
 72 
 73             if (g == 0 && i >= s.size() && i >= b.s.size()) break;
 74 
 75             int x = g;
 76 
 77             if (i < s.size()) x += s[i];
 78 
 79             if (i < b.s.size()) x += b.s[i];
 80 
 81             c.s.push_back(x % BASE);
 82 
 83             g = x / BASE;
 84 
 85         }
 86 
 87         return c;
 88 
 89     }
 90 
 91     BigInteger operator - (const BigInteger& b) const {
 92 
 93         BigInteger c;
 94 
 95         c.s.clear();
 96 
 97         for (int i = 0, g = 0; ; i++) {
 98 
 99             if (g == 0 && i >= s.size() && i >= b.s.size()) break;
100 
101             int x = g;
102 
103             if (i < s.size()) x += s[i];
104 
105             if (i < b.s.size()) {
106 
107                 if (s[i] < b.s[i]) {
108 
109                     x += BASE;
110 
111                     g = -1;
112 
113                 }
114 
115                 x -= b.s[i];
116 
117             }
118 
119             c.s.push_back(x % BASE);
120 
121         }
122 
123         return c;
124 
125     }
126 
127     BigInteger operator += (const BigInteger& b) {
128 
129         *this = *this + b;
130 
131         return *this;
132 
133     }
134 
135  
136 
137     bool operator < (const BigInteger& b) const {
138 
139         if (s.size() != b.s.size())
140 
141             return s.size() < b.s.size();
142 
143         for (int i = s.size()-1; i >= 0; i--) //從低位開始比
144 
145             if (s[i] != b.s[i])
146 
147                 return s[i] < b.s[i];
148 
149         return false; // 相等
150 
151     }
152 
153     bool operator > (const BigInteger& b) const { return b < *this; }
154 
155     bool operator <= (const BigInteger& b) const { return !(b < *this); }
156 
157     bool operator >= (const BigInteger& b) const { return !(*this < b); }
158 
159     bool operator != (const BigInteger& b) const { return (*this < b || b < *this); }
160 
161     bool operator == (const BigInteger& b) const { return (!(*this < b) && !(b < *this)); }
162 
163 };
164 
165  
166 
167 ostream& operator << (ostream &out, const BigInteger& x) {
168 
169     out << x.s.back();
170 
171     for (int i = x.s.size()-2; i >= 0; i--) {
172 
173         char buf[20];
174 
175         sprintf(buf, "%08d", x.s[i]);
176 
177         for (int j = 0; j < strlen(buf); j++)
178 
179             out << buf[j];
180 
181     }
182 
183     return out;
184 
185 }
186 
187  
188 
189 istream& operator >> (istream &in, BigInteger& x) {
190 
191     string s;
192 
193     if (!(in >> s)) return in;
194 
195     x = s;
196 
197     return in;
198 
199 }
200 
201  
202 
203 #include<set>
204 
205 #include<map>
206 
207 set<BigInteger> s;
208 
209 map<BigInteger, int> m;
210 
211  
212 
213 int main() {
214 
215     BigInteger y;
216 
217     BigInteger x = y;
218 
219     BigInteger z = 123;
220 
221  
222 
223     BigInteger a, b;
224 
225     cin >> a >> b;
226 
227     cout << a - b << "\n";
228 
229     //cout << BigInteger::BASE << "\n";
230 
231     return 0;
232 
233 }

 

 

 

9.malloc, free, new delete

/* new delete使用

*/

#include<stdlib.h>

int main(){

new <=> malloc + 構造construction; //返回是對象類型的指針,(自由存儲區)動態內存分配,malloc從堆中分配,返回值須要強制類型轉換

delete <=> 析構deconstruct + free; 

/*使用new操做符來分配對象內存時會經歷三個步驟:

 

 第一步:調用operator new函數(對於數組是operatornew[])

 *分配一塊足夠大的,原始的,未命名的內存空間以便存儲特定類型的對象。

 第二步:編譯器運行相應的構造函數以構造對象,併爲其傳入初值。

 第三步:對象構造完成後,返回一個指向該對象的指針。

 

使用delete操做符來釋放對象內存時會經歷兩個步驟:

 第一步:調用對象的析構函數。

 第二步:編譯器調用operator delete(或operator delete[])函數釋放內存空間。

總之來講,new/delete會調用對象的構造函數/析構函數以完成對象的構造/析構。而mall *oc則不會。*/

return 0;

}

 

10.inline函數

 1 /* 在線化函數,給編譯器一個提示,要求它試着把全部對fac()的調用在線化
 2 
 3 一個inline函數必須在須要用它的每一個編譯文件裏作徹底同樣的定義
 4 
 5 爲了不錯誤,通常把const(默認具備內部鏈接)和inline放在頭文件裏定義
 6 
 7 */
 8 
 9 inline int fac(int n){
10 
11 return (n<2)?1:n*fac(n-1);
12 
13 }
14 
15  
16 
17 // extern關鍵字,在一個程序裏,一個對象只能定義一次,但能夠有多個聲明(類型必須徹底同樣),file2.c文件裏的extern指明瞭x只是一個聲明,而在file1.c中被定義了
18 
19 // file1.c:
20 
21 int x;
22 
23 int f(){}
24 
25  
26 
27 // file2.c:
28 
29 extern int x;
30 
31 int f();
32 
33 void g(){ x= f(); }
34 
35  

 

11.default parameter默認參數

一般狀況下,函數在調用時,形參從實參那裏取得值。對於屢次調用用一函數同一實參時,C++給出了更簡單的處理辦法。給形參以默認值,這樣就不用從實參那裏取值了。

 1 float volume(float length, float weight = 4, float high = 5)
 2 
 3 {
 4 
 5     return length*weight*high;
 6 
 7 }
 8 
 9 int main()
10 
11 {
12 
13     float v = volume(10);
14 
15     float v1 = volume(10,20);
16 
17     float v2 = volume(10,20,30);
18 
19     cout<<v<<endl;
20 
21     cout<<v1<<endl;
22 
23     cout<<v2<<endl;
24 
25     return 0;

 

規則
1.默認的順序,是從右向左,不能跳躍。
2.函數聲明和定義一體時,默認認參數在定義(聲明)處。聲明在前,定義在後,默認參數在聲明處。
3.一個函數,不能既做重載,又做默認參數的函數。當你少寫一個參數時,系統沒法確認是重載仍是默認參數

 

12. 宏定義與頭文件定義

(1)簡單的宏定義:

#define <宏名>  <字符串>

例: #define PI 3.1415926

(2) 帶參數的宏定義
 

#define <宏名> (<參數表>) <宏體>

例: #define A(x) x

1)文件包含
    能夠把源程序中的#include 擴展爲文件正文,即把包含的.h文件找到並展開到#include 所在處。
2)條件編譯
    預處理器根據#if#ifdef等編譯命令及其後的條件,將源程序中的某部分包含進來或排除在外,一般把排除在外的語句轉換成空行。
3)宏展開
    預處理器將源程序文件中出現的對宏的引用展開成相應的宏 定義,即本文所說的#define的功能,由預處理器來完成。
    通過預處理器處理的源程序與以前的源程序有全部不一樣,在這個階段所進行的工做只是純粹的替換與展開,沒有任何計算功能,因此在學習#define命令時只要能真正理解這一點,這樣纔不會對此命令引發誤解並誤用。

 

define中的三個特殊符號:####@

 

#define Conn(x,y) x##y

#define ToChar(x) #@x

#define ToString(x) #x

(1)x##y表示什麼?表示x鏈接y,舉例說:

int n = Conn(123,456); /* 結果就是n=123456;*/

char* str = Conn("asdf", "adf"); /*結果就是 str = "asdfadf";*/

2)再來看#@x,其實就是給x加上單引號,結果返回是一個const char。舉例說:

char a = ToChar(1);結果就是a='1';
作個越界試驗char a = ToChar(123);結果就錯了;
可是若是你的參數超過四個字符,編譯器就給給你報錯了!

error C2015: too many characters in constant   P

(3)最後看看#x,估計你也明白了,他是給x加雙引號

char* str = ToString(123132);就成了str="123132";

 

頭文件中用到的 #ifndef/#define/#endif 來防止該頭文件被重複引用

#ifndef __struct_h__ // if not define

#define __struct_h__ // define

class Struct{

};

void func();

#endif

 

 

3、繼承

 1 #include<stdlib.h>
 2 
 3 public class B {
 4 
 5 int i;
 6 
 7 char *b;
 8 
 9 public:
10 
11 B();
12 
13 void fun();
14 
15 }
16 
17  
18 
19 class T : public B { // T繼承B,子類自動擁有父類的屬性和行爲
20 
21  
22 
23 void T::fun(){ // 子類重載父類
24 
25 B::fun(); // 繼承父類的行爲
26 
27 /*
28 
29 * 子類特性行爲
30 
31 */
32 
33 }
34 
35 }

 

4、多態

 

  將派生類對象賦值給基類對象、將派生類指針賦值給基類指針、將派生類引用賦值給基類引用,向上轉型指針或引用,而非傳值。

 

抽象類能夠有成員變量,接口不能有。

 

1. 虛基類

 

2.純虛函數與抽象類:

 

 1 #include<stdlib.h>
 2 /* 咱們把包含純虛函數的類稱之爲抽象類
 3 對於抽象類來講,C++是不容許它去實例化對象的。也就是說,抽象類沒法實例化對象。
 4 抽象類只用來繼承
 5 */
 6 class T : public B { // T繼承B,子類自動擁有父類的屬性和行爲
 7 public:
 8     virtual void fun2(); // virtual func,函數體能夠有內容{。。。}
 9     
10     virtual void fun() = 0; // 純虛函數
11     
12 }
13 
14 int main(){
15     
16     return 0;
17 }
相關文章
相關標籤/搜索