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;
}
例如:
Struct stu{
double a; //8位
int i; //加8位(本來只有4位)等於16位
char c; //因爲Int後4位沒有佔用,char直接佔用,16不改變
char c2; // 同上
}
sizeof(stu) = 16
java用new建立對象時的內存分配。
Stu s; //java中使用這語句時,定義標識符s,沒有實際空間,只有new才分配空間建立對象
Stu stu; //在棧中申請空間,不能有括號,在程序結束後自動執行析構函數銷燬對象
Stu stu1 = new Stu(); //在堆中申請空間
Stu *pstu = &stu1; //new建立類對象須要指針接收,一處初始化,多處使用
Stu *stu2 = new Stu();
delete pstu; //刪除對象new建立類對象使用完需delete銷燬
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");
}
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;
}
在某些情況下,類內成員變量須要動態開闢堆內存,若是實行位拷貝,也就是把對象裏的值徹底複製給另外一個對象,如A=B。這時,若是B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。
深拷貝和淺拷貝能夠簡單理解爲:若是一個類擁有資源,當這個類的對象發生複製過程的時候,資源從新分配,這個過程就是深拷貝,反之,沒有從新分配資源,就是淺拷貝。
所謂淺拷貝,就是說編譯器提供的默認的拷貝構造函數和賦值運算符重載函數,僅僅是將對象a中各個數據成員的值拷貝給對象b中對應的數據成員(這裏假設a、b爲同一個類的兩個對象,且用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
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
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
博客:大整數運算符重載: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 }
/* 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;
}
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
一般狀況下,函數在調用時,形參從實參那裏取得值。對於屢次調用用一函數同一實參時,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.一個函數,不能既做重載,又做默認參數的函數。當你少寫一個參數時,系統沒法確認是重載仍是默認參數
(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
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 }
將派生類對象賦值給基類對象、將派生類指針賦值給基類指針、將派生類引用賦值給基類引用,向上轉型指針或引用,而非傳值。
抽象類能夠有成員變量,接口不能有。
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 }