编译器越来越软,规范性越来越弱
# C 部分
# 动态空间
# malloc 分配空间
malloc分配空间 1 2 3 4 5 6 int main () { int *p = malloc (10 * sizeof (int )); if (p == NULL ) printf ("Malloc Error!\n" ); for (int i = 0 ;i < 10 ;i++) *(p + i) = i; for (int i = 0 ;i < 10 ;i++) printf ("%d" , p[i]); }
0123456789
# 高维数组
# 高维数组奇妙写法
高维数组奇妙写法 1 2 3 4 5 6 7 8 9 10 11 12 13 int main () { int a[3 ][3 ]; printf ("%d\n" , (a + 1 )[2 ]); printf ("%d\n" , *(a + 1 + 2 )); int (*p)[3 ][3 ] = &a; int (*p1)[3 ] = a + 1 ; int *p2 = a[0 ]; printf ("%d\n" , (*(a + 1 ))[2 ]); printf ("%d\n" , *(*(a + 1 ) + 2 )); }
6422020
6422020
0
0
# 高维数组初始化
高维数组初始化 1 2 3 4 5 6 7 8 9 10 11 int main () { int arr[5 ] = {10 , 20 , 30 , 40 , 50 }; int b = (arr+1 )[2 ]; printf ("is: %d\n" ,b); int arr2[3 ][3 ] = {{10 , 20 , 30 }, {40 , 50 , 60 }, {70 , 80 , 90 }}; int c = (arr2+1 )[2 ]; printf ("is: %d\n" ,c); int d = (*(arr2+1 ))[2 ]; printf ("is: %d\n" ,d); }
is: 40
is: 6422004
is: 60
# 高维数组的传值
高维数组传值 1 2 3 4 5 6 7 8 9 10 11 void sort (int arr[]) { printf ("%d\n" , &arr); arr[0 ] = 1000 ; } int main () { int a[5 ] = {0 , 1 , 2 , 3 , 4 }; printf ("%d\n" , a[0 ]); printf ("%d\n" , &a); sort(a); printf ("%d\n" , a[0 ]); }
0
6422016
6421984
1000
# 特别注意高维数组传值写法
特殊注意 1 2 3 4 5 6 7 8 9 10 11 12 13 void void1 (int a[][3 ]) {} void void2 (int (*a)[3 ]) {} int main () { int arr[3 ][3 ]; void1(arr); void2(arr); }
# 共用体
共用体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typedef union Node{ int a; char b; } Node; typedef struct Node1 { int a; } Node1; int main () { Node a; a.a = 3 ; printf ("%d\n" , a.a); a.b = 'a' ; printf ("%d\n" , a.a); printf ("%d\n" , sizeof (a)); Node1 b; }
3
97
4
由于共用体成员共享一段内存地址,所以改变其中一个的值其他值也会改变
# 函数指针
# 函数指针
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 int compare1 (void const * A, void const *B) { if (*(int *)A == *(int *)B) return 1 ; return 0 ; } int compare2 (void const * A, void const *B) { if (*(char *)A == *(char *)B) return 1 ; return 0 ; } void search (void *a, void *b, int (*compare)(void const *A, void const *B)) { if (compare(a, b)) printf ("yes!\n" ); else printf ("no!\n" ); } int (*func[])(void const *, void const *) = {compare1, compare2};int main (int argc, char **argv) { int *p1, *p2; char *c1, *c2; p1 = (int *)malloc (4 );p2 = (int *)malloc (4 ); c1 = (char *) malloc (1 ); c2 = (char *) malloc (1 ); *p1 = 1 ; *p2 = 2 ; *c1 = 'a' ; *c2 = 'a' ; search(p1, p2, compare1); search(c1, c2, compare2); search(c1, c2, compare1); printf ("%d\n" , func[0 ](p1, p2)); printf ("%d\n" , argc); }
no!
yes!
yes!
0
1
根据我的理解 void 出现在函数参数里起到的泛型的作用,而 int *compare (…,…) 起到了传一个函数进去的作用
# 宏的特殊用法
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 #define Conn(x, y) x##y #define ToChar(x) *#x #define ToString(x) #x int main () { printf ("%d\n" , Conn(123 , 456 )); printf ("%c\n" , ToChar(5 )); printf ("%s\n" , ToString(123456 )); char *p = ToString(12345678912381098309213 ); printf ("%d\n" , sizeof (p)); printf ("%s\n" , p); return 0 ; }
123456
5
123456
8
12345678912381098309213
# 柔性数组
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 typedef struct _SoftStruct { int len; int array []; } SoftStruct; int main () { SoftStruct a; printf ("%d\n" , sizeof (a)); SoftStruct *p; p = (SoftStruct*) malloc (sizeof (int ) + sizeof (int ) * (10 )); p -> len = 10 ; for (int i = 0 ;i < (p -> len);i++) (p -> array [i]) = i; for (int i = 0 ;i < (p -> len);i++) printf ("%d\n" , p -> array [i]); }
4
0
1
2
3
4
5
6
7
8
9
注意在结构体里最后一个成员变量 int array [] 并没有占空间,使用时才动态分配空间,且得到和其他成员变量连续的内存空间
# 字符串相关
# 初始化
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int main () { char * str = "Hello" ; char str1[5 ] = "Hell" ; char str2[5 ] = {'H' , 'e' , 'l' , 'l' , '\0' }; char str3[5 ] = "Hello" ; printf ("%s\n" , str3); printf ("%d %d %d\n" , str3, str2, str1); printf ("%c\n" , *(str + 1 )); printf ("str1 : %d %s\n" , sizeof (str1), str1); printf ("str2 : %d %s\n" , sizeof (str2), str2); printf ("%d\n" , str1 == str2); str2[2 ] = '\0' ; printf ("str2: %d %s\n" , strlen (str2), str2); printf ("%c\n" , *(str2 + 3 )); int * intP = (int *) malloc (5 * sizeof (int )); intP[4 ] = 5 ; *(intP + 4 ) = 5 ; return 0 ; }
HelloHell
6422017 6422022 6422027
e
str1 : 5 Hell
str2 : 5 Hell
0
str2: 2 He
l
# strcpy 函数
demo2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int main (int argc,char * argv[]) { char buf[2 ]; char *str = "hello world" ; char (*q)[2 ] = &buf; strcpy (buf,str); printf ("buf:%s\nsizeof(buf) = %ld\nstrlen(buf) = %ld\n" , buf,sizeof (buf),strlen (buf)); printf ("%d %d %d\n" , str, &str, buf); char buf1[20 ]; strncpy (buf1,str,20 ); printf ("buf1:%s\nsizeof(buf1) = %ld\nstrlen(buf1) = %ld\n" , buf1,sizeof (buf1),strlen (buf1)); printf ("%d %d %d\n" , str, &str, buf); return 0 ; }
buf:hello world
sizeof(buf) = 2
strlen(buf) = 11
4210688 6422032 6422046
buf1:hello world
sizeof(buf1) = 20
strlen(buf1) = 11
4210688 6422032 6422046
注意 sizeof 是在编译时运算的分配的空间,而 strlen 是运行时遍历到第一个 \0,strcpy 原字符串长度过长时会引起覆盖掉 \0 导致不受控制的内存覆盖
# strcmp 函数
strcmp 1 2 3 4 5 6 7 8 9 10 11 int main () { char a[] = "abc" ; char b[] = "ab" ; char c[] = "ad" ; char d[] = "d" ; printf ("strcmp(\"abc\", \"ab\")=%d\n" , strcmp (a, b)); printf ("strcmp(\"ab\", \"abc\")=%d\n" , strcmp (b, a)); printf ("strcmp(\"ab\", \"ab\")=%d\n" , strcmp (b, b)); printf ("strcmp(\"ad\", \"abc\")=%d\n" , strcmp (c, a)); return 0 ; }
strcmp(“abc”, “ab”)=1
strcmp(“ab”, “abc”)=-1
strcmp(“ab”, “ab”)=0
strcmp(“ad”, “abc”)=1
就是字典序,大于输出 1,小于输出 - 1,等于输出 0.(为啥要记这东西
# 存储区域
char* 与 char[] 1 2 3 4 5 6 int main () { char a[6 ] = "hello" ; char *p = "123" ; strcat (a, p); strcat (p, a); }
注意到,“123” 储存在常量区,而 char *p 在编译时就确定指向了它,不可被更改。而 char a [6] 字符数组在运行时才被初始化为”hello“,相当于在堆上 malloc 了一个空间。
# 指针初步
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 void swap (int * a, int * b) { int * temp = a; a = b; b = temp; } void swap1 (int *a, int *b) { int t = *a; *a = *b; *b = t; } int main () { int a = 10 ; int b = 20 ; swap(&a,&b); printf ("a is %d, b is %d\n" , a,b); swap1(&a,&b); printf ("a is %d, b is %d\n" , a,b); return 0 ; }
a is 10, b is 20
a is 20, b is 10
demo2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 void func (int a) { printf ("%x\n" , &a); } int main () { int a = 10 ; int * p; p = &a; int *p1; *p1 = 10 ; printf ("%x %x\n" , p1, *p1); printf ("p is %x\n" , p); printf ("*p is %d\n" , *p); int * p2 = (int *)0x61fe04 ; printf ("*p2 is %d\n" , *p2); printf ("%x " , &a); func(a); }
c013c0 a
p is 61fe04
*p is 10
*p2 is 10
61fe04 61fde0
# C++ 部分
# 运算优先级
demo1.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 struct A { int u; }; int main () { A a[10 ]; for (int i = 0 ;i < 10 ;i++) a[i].u = i + 1 ; A* p = a; cout << (++p)->u << endl ; cout << p - a << endl ; for (int i = 0 ;i < 10 ;i++) cout << a[i].u << " " ;cout <<endl ; cout << ++p->u << endl ; cout << p - a << endl ; for (int i = 0 ;i < 10 ;i++) cout << a[i].u << " " ;cout <<endl ; }
2
1
1 2 3 4 5 6 7 8 9 10
3
1
1 3 3 4 5 6 7 8 9 10
demo2.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int main () { int a[10 ]; for (int i = 0 ;i < 10 ;i++) a[i] = 10 - i; int *p = a; cout << *p++ << endl ; cout << p - a << endl ; for (int i = 0 ;i < 10 ;i++) cout << a[i] << " " ;cout <<endl ; for (int i = 0 ;i < 10 ;i++) a[i] = 10 - i; p = a; cout << (*p)++ << endl ; cout << p - a << endl ; for (int i = 0 ;i < 10 ;i++) cout << a[i] << " " ;cout <<endl ; p = a; cout << *p + 2 << endl ; }
10
1
10 9 8 7 6 5 4 3 2 1
10
0
11 9 8 7 6 5 4 3 2 1
13
# (伪)局部函数
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 int main () { struct { void operator () () { cout << "HELLO" << endl ; } int operator () (int a, int b) { return a + b; } } foo; foo(); cout << foo(1 , 2 ); }
HELLO
3
# 纯虚函数和抽象类
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class A { public : virtual void func () = 0 ; }; class B : public A{ public : void func () { cout << "Hello" ; } }; int main () { B b; b.func(); return 0 ; }
Hello
demo2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class A { public : void func () { cout << "Hello!" ; } }; class B : public A{ public : void func () =delete ; }; class C { public : C()=delete ; }; int main () { B b; return 0 ; }
# 仿函数
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Class_Func { public : bool operator () (int num) { return num == 10 ? 1 : 0 ; } private : }; bool func (int num) { return num == 10 ? 1 : 0 ; } void cal (int a[], int len, Class_Func f) { int res = 0 ; For(i, 0 , len) if (f(a[i])) res++; printf ("%d\n" , res); } void cal (int a[], int len, bool (*func)(int num)) { int res = 0 ; For(i, 0 , len) if (func(a[i])) res++; printf ("%d\n" , res); } int main () { int a[5 ] = {10 , 1 , 10 , 1 ,10 }; Class_Func t; cal(a, 5 , t); cal(a, 5 , Class_Func()); cal(a, 5 , func); return 0 ; }
3
3
3
# 分配内存
# bad 版
stringbad.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class StringBad { private : char * str; int len; static int num_strings; public : StringBad(const char * s); StringBad(); ~StringBad(); friend std ::ostream & operator <<(std ::ostream & os, const StringBad & st); };
stringbad.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 using std ::cout ;int StringBad::num_strings = 0 ;StringBad::StringBad(const char * s) { len = std ::strlen (s); str = new char [len + 1 ]; std ::strcpy (str, s); num_strings++; cout << num_strings << ": \"" << str << "\" object created\n" ; } StringBad::StringBad() { len = 4 ; str = new char [4 ]; std ::strcpy (str, "C++" ); num_strings++; cout << num_strings << ": \"" << str << "\" default object created\n" ; } StringBad::~StringBad() { cout << "\"" << str << "\" object deleted, " ; --num_strings; cout << num_strings << " left\n" ; delete [] str; } std ::ostream & operator <<(std ::ostream & os, const StringBad & st){ os << st.str; return os; }
vegnew.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <iostream> using std ::cout ;#include "strngbad.h" void callme1 (StringBad &) ; void callme2 (StringBad) ; int main () { using std ::endl ; { cout << "Starting an inner block.\n" ; StringBad headline1 ("Celery Stalks at Midnight" ) ; StringBad headline2 ("Lettuce Prey" ) ; StringBad sports ("Spinach Leaves Bowl for Dollars" ) ; cout << "headline1: " << headline1 << endl ; cout << "headline2: " << headline2 << endl ; cout << "sports: " << sports << endl ; cout << endl ; callme1(headline1); cout << "headline1: " << headline1 << endl ; callme2(headline2); cout << "headline2: " << headline2 << endl ; cout << endl ; cout << "Initialize one object to another:\n" ; StringBad sailor = sports; cout << "sailor: " << sailor << endl ; cout << "Assign one object to another:\n" ; StringBad knot; knot = headline1; cout << "knot: " << knot << endl ; cout << endl ; cout << "Exiting the block.\n" ; } cout << "End of main()\n" ; return 0 ; } void callme1 (StringBad & rsb) { cout << "String passed by reference:\n" ; cout << " \"" << rsb << "\"\n" ; } void callme2 (StringBad sb) { cout << "String passed by value:\n" ; cout << " \"" << sb << "\"\n" ; }
Starting an inner block.
1: “Celery Stalks at Midnight” object created
2: “Lettuce Prey” object created
3: “Spinach Leaves Bowl for Dollars” object created
headline1: Celery Stalks at Midnight
headline2: Lettuce Prey
sports: Spinach Leaves Bowl for Dollars
String passed by reference:
“Celery Stalks at Midnight”
headline1: Celery Stalks at Midnight
String passed by value:
“Lettuce Prey”
“Lettuce Prey” object deleted, 2 left
headline2:
Initialize one object to another:
sailor: Spinach Leaves Bowl for Dollars
Assign one object to another:
3: “C++” default object created
knot: Celery Stalks at Midnight
Exiting the block.
“Celery Stalks at Midnight” object deleted, 2 left
“Spinach Leaves Bowl for Dollars” object deleted, 1 left
" 衑?
# good 版
good 版就是重写了 BadString (const BadString & s)、BadString & operator = (const BadString & s) 之类的一切可能产生复制对象 的函数,把其中的 str = s.str 改成 str = new char [strlen (s.str) + 1], strcpy (str, s.str)。一定要手动新分配内存。
# 构造函数和析构函数
# 对象和指针的析构顺序
stock.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Stock { private : string company; long shares; double share_val; double total_val; void set_tot () {total_val = share_val * shares;} public : Stock(); Stock(const string &co); virtual ~Stock(); void buy (long num, double price) ; void sell (long num, double price) ; void update (double price) ; void show () ; };
stock.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Stock::Stock(){ cout << "Stock default constructor is called!" << endl ; company = "no name" ; } Stock::Stock(const string &co):company(co){ cout << "Stock constructor with parameter is called!" << endl ; } Stock::~Stock(){ cout << "Bye!" << " " << company << endl ; } void Stock::show(){ cout << company << endl ; } int main () { Stock B = (string )"B" ; Stock* A = new Stock(); delete A; }
Stock constructor with parameter is called!
Stock default constructor is called!
Bye! no name
Bye! B
可以注意到默认的析构函数总是在出栈时调用(即总在手写实现 delete 后面
# 继承的构造与析构
demo.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class BaseDemo { public : BaseDemo() { cout << "This is the BaseDemo constructor. \n" ; } ~BaseDemo() { cout << "This is the BaseDemo destructor.\n" ; } virtual void show () { cout << "show from Base Demo!" << endl ; } }; class DeriDemo : public BaseDemo{ public : DeriDemo() { cout << "This is the DeriDemo constructor.\n" ; } ~DeriDemo() { cout << "This is the DeriDemo destructor.\n" ; } virtual void show () { cout << "show from DeriDemo" << endl ; } }; int main () { DeriDemo *A = new DeriDemo(); delete A; cout << "\n" ; BaseDemo *B = new DeriDemo(); B -> show(); return 0 ; }
This is the BaseDemo constructor.
This is the DeriDemo constructor.
This is the DeriDemo destructor.
This is the BaseDemo destructor.
This is the BaseDemo constructor.
This is the DeriDemo constructor.
show from DeriDemo
可以注意到构造函数从基类开始,析构函数从派生类开始。此外,指针 new 的或者 malloc 分配的对象地址不手动删除时不会被自动 delete 掉。这里还可以注意下 B 虽然是基类指针却指向一个派生类,而虚函数 show 很好的体现了指针对象的类别。
而特别地,C++ 中将类的析构函数写成虚函数是很好的习惯。防止在多态时用基类指针指向派生类时,析构却没有调用派生类析构函数导致内存泄漏。
进一步地,为什么要用基类指针指向派生类呢?这就是继承与多态的内容了。可以理解多态为 “接受来自基类的同一指令,但却根据不同的派生类产生不同的行为”。譬如基类是 “图形”,而它的派生类有 “矩形”“三角形”“圆” 等等。而图形都可以求面积,所以 getArea () 函数应该写在基类里,并且写成虚函数,根据不同的派生类进行不同的面积公式计算。而 “接受同一指令” 即需要使用基类指针。即我不关心你究竟是三角形还是矩形,我只关心其可以求面积。事实上就是把接口与实现分离 .{dot},基类的虚函数说明了对外界能使用的函数信息,不同的派生类进行自己独特的实现。
# 多继承
djc.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class A {public : A(){ printf ("A()\n" ); } virtual ~A(){ printf ("~A()\n" ); } }; class B : public A{public : B(){ printf ("B()\n" ); } virtual ~B(){ printf ("~B()\n" ); } }; class C {public : C(){ printf ("C()\n" ); } virtual ~C(){ printf ("~C()\n" ); } }; class D : public C, public B{public : D(){ printf ("D()\n" ); } virtual ~D(){ printf ("~D()\n" ); } }; int main () { D d () ; return 0 ; }
C()
A()
B()
D()
~D()
~B()
~A()
~C()
D 继承自 C,B,B 继承自 A。同级间写在前面的先构造,即要构造 D,先构造 C,然后构造 B,要构造 B,先构造 A,于是构造顺序为 C-A-B-D
# 局部类
jbl.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 int main () { class c4 { public : int a; void foo () {a = 4 ;} }; class c4 ff ; ff.foo(); cout << ff.a << endl ; return 0 ; }
# 类继承
这部分不想给 demo 了,主要是注意几个点:
demo1 1 2 3 4 5 6 A a; A a () ; A a = b; A a; a = b;
demo2 1 2 3 4 5 6 7 8 void func (A a) {} int main () { A a; func(a); }
demo3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Person {public : Person(int _id, char * _name); ~Person(); Person(); Person(const Person& pr)=delete ; public : Person& operator =(const Person& pr)=delete ; private : int id; char * name; private : static int counter; };
# 枚举类
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 enum Weekdays{ MON, TUE, WED, THU = 6 , FRI, SAT, SUN }; int main () { Weekdays rua = WED; switch (rua){ case MON: break ; case TUE: break ; } return 0 ; }
# 命名空间
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 namespace myspace1{ extern int gvar; using std ::cout ; using std ::endl ; class myclass { public : void print () { cout <<"in space1,gvar=" <<gvar<<endl ; } }; } namespace myspace2{ using std ::cout ; using std ::endl ; int i=5 ; class myclass { public : void print () { cout <<"in space2" <<endl ; } }; namespace nestedspace { void ExternFunc () ; } } int myspace1::gvar=1 ;void myspace2::nestedspace::ExternFunc(){ cout <<"in nestedspace" <<endl ; } int main (int argc,char * argv[]) { myspace1::myclass obj1; obj1.print (); myspace2::myclass obj2; obj2.print (); myspace2::nestedspace::ExternFunc(); }
in space1,gvar=1
in space2
in nestedspace
注意” 外部定义 “+” 内部声明 “和” 内部声明 “+” 外部实现 “的操作,虽然我也不知道为啥,明明内部定义 + 内部实现挺不错啊据说老版本会报错
匿名命名空间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using namespace std ;namespace { double dvar=1.8 ; } void show1 () { cout <<"dvar:" <<dvar<<endl ; } int main (int argc,char * argv[]) { void show2 () ; show1(); show2(); } #include <iostream> using namespace std ;double dvar=2.8 ;void show2 () { cout <<"dvar:" <<dvar<<endl ; }
1.8
2.8
匿名命名空间可以将 struct 和 class 的对象前都加上”static“修饰,如果定义了相同的变量名也不会报错。匿名命名空间中的变量仅在包含该匿名命名空间的源文件中可见。
# 模板
模板函数 1 2 3 4 5 6 7 8 9 10 template <typename T> int compare (const T &a, const T &b) { return a == b ? 0 : (a > b ? 1 : -1 ); } int main () { cout << compare(1 , 2 ) << endl ; cout << compare("a" , "b" ) << endl ; cout << compare('a' , 'b' ) << endl ; return 0 ; }
-1
1
-1
模板类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template <class T > class Queue { public : Queue (); T &front () ; const T &front () const ; void push (const T &) ; void pop () ; bool empty () const ; private : }; int main () { Queue<int > Q; Queue<char > Q1; return 0 ; }
# 嵌套类
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class c1 {public : int a; void foo () ; class c2 { public : int a; void foo () ; } b; }; void c1::foo(){ a = 1 ; } void c1::c2::foo(){ a = 2 ; } int main () { class c1 f ; f.foo(); f.b.foo(); cout << f.a << endl ; cout << f.b.a << endl ; return 0 ; }
1
2
# 虚函数
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class A { public : virtual void print () {cout <<"This is A" <<endl ;} }; class B : public A{ public : void print () {cout <<"This is B" <<endl ;} }; int main () { A a; B b; A *p1 = &a; A *p2 = &b; p1->print (); p2->print (); return 0 ; }
This is A
This is A
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class A { public : virtual void print () {cout <<"This is A" <<endl ;} }; class B : public A{ public : virtual void print () {cout <<"This is B" <<endl ;} }; int main () { A a; B b; A *p1 = &a; A *p2 = &b; p1->print (); p2->print (); return 0 ; }
This is A
This is B
# 异常
char*异常 1 2 3 4 5 6 7 8 9 10 11 12 void divide (int a, int b) { if (b == 0 ) throw "rua!" ; a /= b; } int main () { try { divide(1 , 0 ); }catch (const char * e){ cout << e << endl ; } return 0 ; }
rua!
自定义异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class myexception : public std ::exception {public : myexception(std ::string s) : message(s){ } virtual const char *what () { return message.data(); } private : std ::string message; }; void Func () { try { int *p = NULL ; if (p == NULL ) { throw myexception("p is NULL" ); } } catch (myexception e) { printf ("%s\n" , e.what()); throw ; }catch (std ::exception e) { printf ("%s" , e.what()); } } int main () { try { Func(); } catch (myexception e){ printf ("%s\n" , e.what()); } catch (...){ } return 0 ; }
p is NULL
p is NULL
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Myexception : public std ::exception {public : Myexception(std ::string s){ message = new char [s.length() + 1 ]; for (int i = 0 ;i < s.length();i++) message[i] = s[i]; } Myexception(){ message = NULL ; } virtual const char *what () { if (message == NULL ) throw "unknown exception!" ; return message; } virtual ~Myexception(){ delete message; } private : char *message; }; void foo () { char *p = NULL ; if (p == NULL ) throw Myexception(); } int main () { try { foo(); } catch (Myexception e){ try { printf ("%s\n" , e.what()); }catch (const char * s){ printf ("%s\n" , s); } } catch (...){ } return 0 ; }
unknown exception!
我验证了 virtual const char *what () 里面也可以抛异常
# 引用
demo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 int val[10 ];int &put (int idx) { return val[idx]; } void swap (int &a, int &b) { a ^= b ^= a ^= b; } int res;int fn1 (int r) { res = r * r; return res; } int & fn2 (int r) { res = r * r; return res; } int main () { put (0 ) = 1 ; put (1 ) = 2 ; For(i, 0 , 2 ) printf ("%d\n" , val[i]); int a = 1 , b = 2 ; int &ra = a, &rb = b; swap(ra, rb); printf ("%d %d\n" , a, b); int r = 3 ; int x = fn1(r), y = fn2(r); int &ry = fn2(r); cout << x << " " << y << " " << " " << ry << endl ; return 0 ; }
1
2
2 1
9 9 9
demo2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 struct struct_A { int a[10 ]; int & operator [](int idx){ return a[idx]; } }; void func1 (int a) {} void func2 (int *a) {} void func3 (int & a) {} void func4 (const int & a) {} int main () { struct_A a; a[3 ] = 10 ; cout << a.operator [](3 ) << endl ; int b = 10 ; int & rb = b; printf ("%d %x %x\n" , rb, &b, &rb); return 0 ; }
10
10 61fdec 61fdec
# 友元
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class A { friend class B ; friend void print (const A &a) ; friend int main () ; private : int value = 0 ; public : }; void print (const A &a) { printf ("%d from A!\n" , a.value); } class B { private : A a; public : void set () { a.value = -100 ; } void print () { printf ("%d\n" , a.value); } }; int main () { B b; b.print (); b.set (); b.print (); A a; print (a); return 0 ; }
0
-100
0 from A!
# 重载运算符
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Time { friend Time operator += (Time& A, const Time& B); friend ostream & operator << (ostream &os, const Time& A); private : int minute, hour; public : Time operator + (const Time& B){ Time res; res.hour = this -> hour + B.hour + (this -> minute + B.minute) / 60 ; res.minute = (this -> minute + B.minute) % 60 ; return res; } friend ostream & operator << (ostream &os, const Time& A){ os << "(" << A.hour << ":" << A.minute << ")" ; return os; } ostream & operator << (ostream &os){ os << "(" << hour << ":" << minute << ")" ; return os; } void set (int hour, int minute) { this -> hour = hour; this -> minute = minute; } void print () { printf ("%d:%d\n" , hour, minute); } }; Time operator += (Time& A, const Time& B){ A = A + B; return A; } int main () { Time a, b; a.set (1 , 30 ); b.set (3 , 40 ); a = a + b; a.print (); a += b; a.print (); cout << a << b << endl ; a << cout << b << endl ; return 0 ; }
5:10
8:50
(8:50)(3:40)
(8:50)(3:40)
我发现在重载运算符时,写不写 friend 的一个直接影响是 operator 函数参数的个数。如果写了 friend 就能填两个,否则只能填一个
demo2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class A { private : int a[10 ]; void set () { for (int i = 0 ;i < 10 ;i++) a[i] = -i; } public : int & operator [] (int idx){ return a[idx]; } void operator () () { set (); return ; } A & operator << (ostream &os){ os << a[3 ]; return *this ; } }; int main () { A a; a[2 ] = 114514 ; a(); printf ("%d %d\n" , a[2 ], a[3 ]); (a << cout ) << cout ; return 0 ; }
-2 -3
-3-3
# new 和 delete
demo1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class T { public : T(){ cout << "T()" << endl ; w = 0 ; } ~T(){ cout << "~T()" << endl ; } int w; }; int main () { T t = T(); t.w = 10 ; T* p = new (&t) T; cout << t.w << endl ; char a[sizeof (T)]; p = new (a) T; p = new (a) T; p = new T(); return 0 ; }
T()
T()
0
T()
T()
T()
~T()
# const 关键字
指针 1 2 3 4 5 6 7 8 9 10 11 int main () { char s[] = "abc" ; char *const p1 = s; cout << *p1 << endl ; char const *p2 = s; const char *p3 = s; return 0 ; }
a
demo2 1 2 3 4 5 6 7 8 9 10 11 12 13 void func1 (int *const a) { } void func2 (int const *a) { } int main () { int *a = new int (3 ); func1(a); func2(a); return 0 ; }
demo3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 int d = 0 ;class A {public : A(){} void func1 () { b = 10 ; } const void func2 () { b = 10 ; } void func3 () const { d = 10 ; } const int a = 1 ; int b = 2 ; }; int main () { const A a; A b; cout << a.a << " " << a.b << endl ; b.func2(); cout << b.a << " " << b.b << endl ; }
1 2
1 10