0、附
vs2019快捷键:ctrl + k + f 代码自动对齐 ctrl + k + c 注释 ctrl + k + u取消注释
c++关键词:cohesion(凝聚性) polymorphic 多态
1、关于对象 1.对象的定义,声明和初始化
关于定义:定义必须以字母或者下划线开头,不能包括空白。变量声明的实质:将一段计算机内存和变量名关联起来 。构造只能进行一次
关于声明:变量声明是一个语句,指定变量名称和类型,常常声明和定义会同步进行,它只是说明变量定义在程序的其他地方,在其他地方已经完成了定义,这里只是说明有这么个变量存在。
关于初始化:将初始值赋给变量的声明称为初始化 ,一般有三种方式:
1 2 3 int m1 = 10 ; int m2 (10 ) ; int m3 {3 };
2.动态内存分配
关键词:new 分配一段空间,返回值是该类型的一个指针(在堆区动态申请内存)
1 2 3 4 5 int *a = new int ;int *b = new int (10 ); int *c = new int [10 ]; int **p = new int *[10 ];
new和malloc区别:new是操作符,malloc是函数,new会调用构造函数,malloc不会
如果new时有[],delete也需要[]。
只有new分配的空间,才能执行delete。
delete回收一段数组时,(参数是数组名),析构只会执行一次,只回收第一个了。
3.引用(Reference)
引用就是给变量取了另外一个名字
变量在函数参数表只是声明,传入实参才是初始化。
引用绑定完不能去绑定别的
引用无法绑定引用
没有引用数组,也没有指向引用的指针
1 2 3 typename &refname = name; void fun (int &i) ;
4.const(对标宏) 1 2 3 4 5 6 const int x = 12 ; string s = "abc" ;char *const p = s; const char *p = s; char const *p = s;
注意:c语言声明数组长度必须已知。
1 bool operator ==( const Integer& rhs) const ;
2、输入输出 1.cout函数格式控制
1 2 3 4 5 6 7 8 #include <iomanip> cout.flags (ios::left); cout << setw (10 ) << -456.98 << "The End" << endl; cout << left << setw (10 ) << -456.98 << "The End" << endl; cout << internal << setw (10 ) << -456.98 << "The End" << endl; cout << right << setw (10 ) << -456.98 << "The End" << endl;
1 2 3 4 #include <iomanip> cout.setf (ios::fixed); cout << fixed << setprecision (N) <<X<< endl; cout.unsetf (ios::fixed);
2.输入:getline函数(对比cin)
3、class 1.类的定义
2.:: resolver
限定访问范围,在限定范围的函数中,如果不加::,则是默认调用限定范围内,加上::则且无前缀则可以认为是全局访问的函数。
1 2 void A::f1 () {}void ::f2 (){}
header=interface 提供user和class的作者间的接口。
在预编译时会将头文件里的代码与main文件链接在一起。
#include: “ ” 和<>的区别:<>在系统预设的环境中寻找,””完全与实现相关,一般会先去当前目录下寻找。
4. 类中嵌套类的使用
由于每个头文件中都会引用其他文件,会导致重定义。
解决办法:头文件保护
1 2 3 4 #ifndef A_H #define A_H ...#endif
5. 构造函数
因为class的变量一般是private,所以通过一个构造函数去使用class中的变量。
析构函数不能带参数,构造函数是能带参数的。
构造函数不带返回值,当对象被创建时自动被调用。
难点:默认构造函数,不适用初始化列表,直接在构造函数内部构造,则被构造的变量需要有一个默认的构造函数
如果成员变量里有const修饰的,必须要用初始化列表进行初始化,不能用赋值 !
默认构造函数:如果我们没有写构造函数,系统会自动帮我们补上一个默认构造函数,如果我们写了构造函数,默认构造函数将被取缔,但我们可以手动添加一个默认构造,
添加方式有:
添加一个什么都不做的:A2();
添加一个所有参数都有默认值的构造:A2(int a =10);
一个类只会有一个构造函数!
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 class A {private : int x;public : A (int y = 3 ){ x = y; } int A::add (int m) { } void A::print () const { } }class A2 {private : int a2;public : A2 (int m):A2 (m){}; A2 (); A2 (){a2 = 10 ;} }class B {private : int m; int n; }class C {private : int a; B b;public : C (int x1,int m,int n = 5 ):a (x1),b (m,n){} } void foo () const {} }int main () { A t (10 ) ; A a1[3 ] = {A (1 ), A (2 ), A (3 )}; A a2[3 ] = {A (1 ), A (2 )}; B b1[3 ]; }
6. this关键词
1 2 3 4 5 void Point::print (Point *this ) ; Point a; a.print (); Point::print (&a);
7.inline function (内联函数)
定义:简单来说就是编译时直接展开代码,减少开销,所以会增大可执行文件体积,所以适合一些较小的函数,两到三行就能解决的。
如果声明和定义在不同文件,(声明在头文件),会报错 !必须在完整定义放在头文件中。
实现:在函数定义 前加上inline关键词:(函数声明前可以不加)
1 2 3 inline void f (int x) { cout << x << endl; }
8.友元函数
友元函数不是一个类的成员函数,但是它可以访问类的private变量,它没有this指针。
必须要在函数内部声明,且一个友元函数可以是多个类的朋友,在多个类中分别声明。
一个类的成员函数可以成为其他类的友元函数,在声明为另一个类的friend,需要将原类的作用域加上。
可以将一个类作为另一个类的友元类,原类中的所有函数都是另一个类的友元函数,
友元关系不被继承 ,不具有传递性,且是单向的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void print (Point &a) ;class SpecialPoint { };class ManagePoint {public : double distance (Point &a, Point &b) ; }; class Point { friend SpecialPoint; public : Point (double x,double y):m_x (x),m_y (y){} friend void print (Point &a) ; friend double ManagePoint::distance (Point &a, Point &b) ; private : double m_x; double m_y; };
9.static变量
静态成员变量属于整个类所有,所有对象共享类的静态成员变量
静态成员变量生命周期不依赖于任何变量,为程序的生命周期。
可以通过类名直接访问共有静态成员变量,可以通过对象名访问共有静态成员变量。
静态成员变量在类外单独分配空间。
4、composition & Inheritance (组合与继承) 1.composition
1 2 3 4 5 6 7 class SavingsAccount { SavingsAccount::SavingsAccount (const char * name, const char * address, int cents): m_saver (name, address), m_balance (0 , cents) {} void SavingsAccount::print () { m_saver.print (); m_balance.print (); } }
所有的迁入对象都会初始化,如果没有提供足够的参数,会调用默认的构造函数
2.inheritance
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 class A {public : A (int x1, int y1):x (x1),y (y1){} void print () {} A ()protected : int m; int x,y; };class C : public A {public : C (int i1,int i2, int i3):A (i1,i2),z (i3){} void set () {m = 1 }; void print () {} private : int z; }int main () { C m; m.x = 1 ; m.Base:print (); }
5、多态 1.继承体系
在一个继承体系中,如果存放不同对象,用一个列表存储,每一个存储基类指针。
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 shape {private :public : void move () {} virtual void render () {} };class ellipse :public shape { public : void render () {} };class circle :public ellipse { void render () {} };void foo (shape *s) { s->render (); }
2.Polymorphism(多态性)
Upcast: take an object of the derived class as an object of the base one.
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 class Shape { public : Shape (); virtual ~Shape (); virtual void render () ; void move (const Point&) ; virtual void resize () ; protected : Point center; };class Ellipse : public Shape{public : Ellipse (float major,float minor); virtual void render () ;protected : float major_axis,; float minor_axis; };class Circle : public Ellipse{public : Circle (float radius); virtual void render () ; virtual void resize () ; virtual float radius () ;protected : float area; }
virtual关键词:
核心是为了让程序只调用一个函数。可以实现多种功能,在C++程序类的继承中,实现函数的重写(Override)
加入virtual前缀的是虚函数,基类有virtual修饰,派生类的同名函数也会被virtual关键词修饰
在以下的代码中,如果分别定义一个person类的变量p,student类的变量s,没有virtual关键词,那么调用print函数会分别调用,但如果我生成两个person类的指针分别指向p,s,再调用这两个指针,则都会调personA中的函数,加上virtual,则会分别调用两个函数。
有意思的事:那个指向s的指针,他会存下变量,但不能调用student中有person没有的函数?
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 class person {public : person (string n):name (n){ std::cout << "person: ()" << std::endl; } virtual void print () { cout << name << endl; }protected : string name; };class student :public person{public : student (int i, string n):id (i),person (n){ cout << "student:()" << endl; } void print () { cout << name << endl; cout << id << endl; } void printid () { cout << id << endl; }private : int id; };
再看以下测试代码:(椭圆,圆的例子)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Ellipse elly (20F , 40F ) ;Circle circ (60F ) ; elly = circ; Ellipse *elly = new Ellipse (20F , 40F ); Circle *circ = new Circle (60F ); elly = circ;void func (Ellipse& elly) { elly.render (); }Circle circ (60F ) ; func (circ);
注意:
如果基类的析构函数要被继承,把它设置为virtual,否则派生类在析构时只会析构基类的部分,不会析构额外的部分。
如果基类的虚函数后加const,派生类相应的函数没有加const,那么虚函数没有起到相应的作用,如果派生类相应的函数也加const,虚函数机制又发挥相应的作用了
3.override关键词
必须存在于继承关系中,重写只能出现在子类中,且函数声明必须和基函数一直(返回值,参数列表都要一致)
如果是overloading(重载),参数必须不一致
目的:1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。
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 class person {public : person (string n):name (n){ std::cout << "person: ()" << std::endl; } virtual void print () { cout << "This is a person " << name << endl; }protected : string name; };class student :public person{public : student (int i, string n):id (i),person (n){ cout << "student:()" << endl; } void print () override { person::print (); cout << "This is his id: " << id << endl; } void printid () { cout << id << endl; }private : int id; };
4.抽象类
含有纯虚函数的是抽象类:定义为纯虚函数后,该类不能生成对象,只能派生
派生类要是没有实现抽象类,则派生类还是抽象类
纯虚函数的声明:
1 2 3 4 5 6 7 8 9 class CDevice {public : virtual ~CDevice () {} virtual int read (...) = 0 ; virtual int write (...) = 0 ; virtual int open (...) = 0 ; virtual int close (...) = 0 ; virtual int ioctl (...) = 0 ; };
6、拷贝构造 1.类内部的引用
如果类的变量有引用,必须要用一个初始化列表来给引用绑定初值(不能后面用赋值)
如果类的参数中有引用,且声明为const,那么这个变量在函数内部不能被修改,但是他所绑定的对象在函数外部还是可以被修改的,相当于声明这个函数不会修改这个值。
1 2 3 4 5 void func (const int & y, int & z) { z = z * 5 ; y += 8 ; };
引用作为返回值,引用作为函数返回值实际是一个指向返回值的隐式指针,如果类返回一个引用,这个引用不能绑定局部变量(会被销毁!)
1 2 double &operator [](int i); double operator [](int i)const ;
把一个未声明对象的构造函数作为形参传入,需要用new分配动态空间。
1 LinkList ll (*new StrNode(word)) ;
2.拷贝构造
1 2 3 4 5 Person baby_a ("Fred" ) ; Person baby_b = baby_a; Person baby_c ( baby_a ) ; fun (baby_a);
3.浅拷贝与深拷贝
浅拷贝:
由系统提供的拷贝,可以理解为用等号一个个赋值。(指针也会直接赋值)
那么如果原指针指向的内容被释放,拷贝后的指针无法正常释放。
当类中无拷贝构造时,系统会设置一个默认的拷贝构造,是浅拷贝
会出现doublefree的问题。
深拷贝
如果类中有动态内存申请,必须重写拷贝构造,让新的指针指向新的空间、
7、重载 1.conversion operation 1 2 3 4 operator double () const { return numerator/(double )denomirator; }
2.函数重载: 在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class printData { public : void print (int i) { cout << "整数为: " << i << endl; } void print (double f) { cout << "浮点数为: " << f << endl; } void print (char c[]) { cout << "字符串为: " << c << endl; } };
3.运算符重载
函数名:类名 operator”符号”,形式参数里的形式:const 类名&。
可以用作成员函数,也可以用作全局函数,全局的重载函数还可以成为一个友元函数
关于返回值:
如果是<,>,==,返回bool类型的返回值。
如果是+,-,返回一个新的对象
1 2 3 4 5 6 7 8 9 10 11 Box operator +(const Box&, const Box&); Box operator +(const Box& b) { Box box; box.length = this ->length + b.length; box.breadth = this ->breadth + b.breadth; box.height = this ->height + b.height; return box; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Integer& Integer::operator ++() { this ->i += 1 ; return *this ; } Integer Integer::operator ++( int ){ Integer old ( *this ) ; ++(*this ); return old; }
重载[]: 必须是一个成员函数,只有一个参数,
重载=:必须是一个成员函数,返回值是一个引用,引用绑定(*this)
1 2 3 4 5 6 7 8 9 T& T::operator =(const T& rhs) { if ( this != &rhs) { } return *this ; }
4.隐式转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class orange {public : orange (apple&){} };void f (orange o) {}int main () { apple a; f (a); }
explicit 关键词可以防止隐式转换,加在函数前
1 2 3 4 5 6 7 8 9 10 class PathName { string name; public : explicit PathName (const string&) ; ~ PathName (); }; ... string abc ("abc" ) ; PathNamexyz (abc); xyz = abc;
5.functor模仿函数与匿名函数(课件里找不到了,先放着吧,用到了再来仔细解释) 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 struct F { void operator () (int x) const { } } F f; f (2 );void transform (vector<int >&v, int (*f)(int )) { }void transform (vector<int >&v, function<int (int )> f) { }class mul_by {public : mul_by (int a):a (a){} int operator () (int x) { return a*x; }private : int x; }int main () { transform (v,[](int x){return x*5 ;}); int a = 7 ; transform (v,[a](int x){return x*7 }); transform (v,mul_by (5 )); }
6.类型转换函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Str { char *m_p; char m_s[10 ];public : Str (char *s){ strcpy (m_s, s); m_p = m_s; } char operator *(){ return *m_p; } char *operator ++(){ return ++m_p; } operator char *(){return m_p;} };
8、stream 流 1.流的引入与优缺点
什么是流?
Common logical interface to a device
advantage
better type safety
extensible (可扩展)
more object - oriented
disadvantage
more verbose(冗长)
might be slower (流与printf有同步机制,降低速度,可以关闭同步)
1 2 3 #include <iostream> #include <ftream #include <sstream>
3.流的信息
流可分为文本流和二进制流,文本流处理ASCll text
<< 向流中写东西, >> 从流中提取东西。
4.几种流(各自都有缓冲区)
关于iostream
ceer:未缓冲的错误(调试)输出,
clog: 缓冲的错误(调试)输出
定义一个流的重载:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 istream& operator >>(istream& is, T& obj) { return is; }class Person {public : friend ostream& operator <<(ostream& os, const Person& p); Person (string name, int age):name (name), age (age) {}private : string name; int age; }; ostream& operator <<(ostream& os, const Person& p) { cout << "name:" << p.name << " age:" << p.age << endl; return os; }
1 2 3 4 5 get (char *buf, int limit, char delim='\n' );getline (char *buf, int limit, char delim='\n' );
1 2 cout<< "Enter a number" ; cout.flush ();
9、template 1.引入
前提:避免重复代码(不要重复自己)
使用模板:generic programming 的一种(泛型编程)。核心:在类与函数的定义中使用一些不同的类型参数 。成立根源:cpp可以实现函数重载
2.函数模板
function template(函数模板)一般完整地放在头文件中 只有在调用时才会产生真正的实例函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void my_swap ( int &x, int &y ) { int tmp = x; x = y; y = tmp; }template <class T > void my_swap ( T &x, T &y ) { T tmp = x; x = y; y = tmp; }int main () { float x = 0.5 , y = 0 ,4 ; my_swap (x,y); my_swap <double >(x,y); }
T可以出现在参数列表,函数主体与返回值中。
不允许隐式转换 !(应该是我调用函数时不能隐式转换把):question:
选择模板执行顺序:参数完全匹配->模板类->需要强制类型转换,模板类中,顺序为参数类型一致(有无 const),然后全特化->偏特化->参数需要强制类型转换。
3.class template(类模板):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 template <class T , int bounds = 100 > class Vector{private : T element; int elements[bounds]; }template <class T > Vector<T>::Vector (int size):element (size){}int main () { Vector<int > v1 (100 ) ; }
类模板可以和继承结合。类模板可以继承类模板,类模板可以继承模板类,类模板可以继承普通类,普通类可以继承模板类
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 60 61 62 63 64 65 66 67 68 69 #include <iostream> using namespace std;template <typename T1, typename T2>class A { T1 x; T2 y; };template <typename T1, typename T2>class B : public A<T2, T1> { T1 x1; T2 y2; };template <typename T>class C : public B<T, T> { T x3; };template <typename T>class D : public A<int , double > { T x4; };class E { int x4; };template <typename T>class F : public E { T X5; };template <typename T>class G { G g; };class H : public F<int > { int h; };int main () { C<int > c; B<int , char *> b; D<float > d; F<bool > f; H g; return 0 ; }
注意:函数模板可以重载,类模板不能重载。(没有引入一个全新的模板或者模板实例,对原来的泛型模板的实例提供另一种定义)
4.模板全特化
(指定的模板实例必须和相应的模板参数列表一一对应)
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 template <typename T1, typename T2>class A { public : void function (T1 value1, T2 value2) { cout<<"value1 = " <<value1<<endl; cout<<"value2 = " <<value2<<endl; } };template <> class A <int , double >{ public : void function (int value1, double value2) { cout<<"intValue = " <<value1<<endl; cout<<"doubleValue = " <<value2<<endl; } };template <typename T> class A <T, double >{ public : void function (T value1, double value2) { cout<<"Value = " <<value1<<endl; cout<<"doubleValue = " <<value2<<endl; } };int main () { A<int , double > a; a.function (12 , 12.3 ); return 0 ; }
5.模板偏特化
偏特化:将部分参数特化为一确定值,将模板参数特化为指针或者其他模板类
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 template <typename T, class N> void compare (T num1, N num2) { cout << "standard function template" << endl; if (num1>num2) { cout << "num1:" << num1 << " > num2:" << num2 <<endl; } else { cout << "num1:" << num1 << " <= num2:" << num2 << endl; } }template <class N> void compare (int num1, N num2) { cout<< "partitial specialization" <<endl; if (num1>num2) cout << "num1:" << num1 << " > num2:" << num2 << endl; else cout << "num1:" << num1 << " <= num2:" << num2 << endl; }template <typename T, class N> void compare (T* num1, N* num2) { cout << "new partitial specialization" << endl; if (*num1>*num2) cout << "num1:" << *num1 << " > num2:" << *num2 << endl; else cout << "num1:" << *num1 << " <= num2:" << *num2 << endl; }template <typename T, class N> void compare (std::vector<T>& vecLeft, std::vector<T>& vecRight) { cout << "to vector partitial specialization" << endl; if (vecLeft.size ()>vecRight.size ()) cout << "vecLeft.size()" << vecLeft.size () << " > vecRight.size():" << vecRight.size () << endl; else cout << "vecLeft.size()" << vecLeft.size () << " <= vecRight.size():" << vecRight.size () << endl; }
10、STL 1.引入
全称:标准模板库 standard template library 源代码建议自行学习。
包括:pair, list, vector, deque, set, 都在std的命名空间下。分为容器,算法。迭代器三大类。
2.container: vector(动态数组) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <vector> vector<T> v1; vector<T> v2 (v1) ; vector<T> v3 (n,i) ;vector<T> v4 (n) ; vector<int > vec_sample (10 ) ; vector<string> vec_sample (10 ) ; vector<int >::itrator p; vec.push_back (i); vec.pop_back (); vec.erase (it); vec.begin (); vec.end (); for (int &x : vec) { x++; }
vector的capacity不是固定的,会随着压入元素而增长,且一般是成倍增长。每增长一次,会把之前的元素拷贝过来。
1 2 vector.reserve (); vector.emplace_back ();
list(双向链表)
迭代时和vector基本一致,迭代器的结束条件是it != list.end(); 具有以下方法。
1 2 3 4 5 6 list<int > l; l.front (); l.back (); l.push_back (item), l.push_front (item) l.pop_back (), l.pop_front () l.remove (item)
deque(两头可变的数组) 这里用到再补充把
forward 这里用到再补充把
map(关联式容器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <map> map<string, float > price; map <int ,string> mapstudent; mapstudent.insert (pair <int , string>(1 ,"student_one" )); mapstudent.insert (map<int , string>::value_type (2 , "student_two" )); mapstudent[3 ] = "student_three" ; for (auto iter = mapstudent.begin (); iter != mapstudent.end (); iter++) { cout << iter->first << " " << iter->second << endl; }for (int index = 1 ; index <= mapstudent.size (); index++) { cout << mapstudent[index] << endl; }
1 2 3 4 5 if (mapstudent["bob" ] ==1 ){}if (mapstudent.count ("bob" )){}if (mapstudent.contains ("bob" )){}
3.algorithms
(和容器没有直接关系,一般的参数是迭代器)
一个例子:copy
1 2 3 4 #include <algorithm> copy (L.begin (), L.end (), v.begin ()); copy (L.begin (), L.end (), ostream_iterator <int >(cout,", " )); copy (L.begin (), L.end (), infix_ostream_iterator <int >(cout,", " ));
4.iterator
1 2 3 4 5 6 7 8 template <class InputIterator , class T >InputIterator find (InputIterator first, InputIterator last,const T &value) { while (first!=last && *first!=value) ++first; return first; }
11、Exceptions 1.read a file: 顺序:
open the file , determine its size, allocate that much memory, read the file into memory, close the file
2.引入异常
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 T &Vector<T>::operator [](int index){ if (idx < 0 || idx >= m_size) { throw VectorIndexError (idx); } return m_elements[idx]; }void func (int i) { Vector<int > v1; v1.emplace_back (2 ); int i = V1[3 ]; }void outer () { try { func (); func2 (); } catch (VectorIndexError& e) { e.diagnostic (); } cout << "Control is here after exception" ; }void outer2 () { String err ("exceptioncaught" ) ; try { func (); }catch (VectorIndexError){ cout << err; throw ; } }void outer3 () { try { outer2 (); }catch (...){ cout << "catch the error" ; } }
1 2 3 4 5 6 7 8 9 10 11 12 void abc (int a) :throw(MathErr){ }void print (int a) :throw(){ }void find (int a) { }
3.异常举例
12、类型转换与命名空间 1.类型转换 类型转换
类型转换分为四种
static_cast 静态转换
支持任何隐式转换类型,但不支持两个不相关的类型进行强制转换(less likely to make mistakes)
dynamic_cast 将一个父类对象的指针转换为子类对象指针或者引用
向上转型(子类->父类)不需要转换
向下转型 (父类->子类),用dynamic_cast是安全的
注意:只能用于含有虚函数的类 ,且它是先分配子类的空间,把他向上转为父类的指针,再往下转换为子类的。
reinterpret_cast 将一种类型转换为另一种不同类型,没有二进制的转换,一般用于指针
const_cast,去掉变量的const属性,方便赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 a = static_cast <int >(d);int i = 10 ;char c = static_cast <char >(i);int a = 7 ;double *p; p = reinterpret_cast <double *>(&a);const int c = 7 ; int *q; q = const_cast <int *>(&c);
2.命名空间
定义:是一个类,函数,变量的逻辑集合,
将函数封装为命名空间
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 namespace old1 { void f () ; void g () ; class Cat { public : void Meow () ; }; }void old1::f () {cout << " " << endl;}int main () { using namespace std; using old::f; using old::cat; foo (); Cat c; }namespace supercalifragilistic { void f () ; } namespace short_ns = supercalifragilistic; short_ns::f ();
13、CMake
CMakelists.txt:(好处:可以跨平台使用)生成帮助编译的东西。
1 2 3 cmake minimum_required (VERSION 2.8 .9 ) project (point_design) add_executable (point_design main.cpp point.cpp)
14、文件读写 1、文件写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <fstream> ofstream o ("map.txt" ,ios::out) ; if (o.is_open ()) { o<<"hello word!" <<endl; o.close (); }
15、随机函数
基本随机函数
1 2 3 4 5 6 7 8 9 10 #include <cstdlib> #include <ctime> srand (int (time (0 )));rand ()%x; rand ()%(b-a)+a; rand ()%(b-a+1 )+a; rand ()%(b-a)+a+1 ; rand ()/double (RAND_MAX);
一个循环生成随机数的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <iostream> #include <ctime> using namespace std; int main () { srand ((unsigned )time (NULL )); for (int i = 0 ; i < 10 ; i++) { int j = rand () % 10 ; cout << j << endl; } system ("pause" ); return 0 ; }
16、string类的延伸使用 1 2 3 4 str.append ("abc" ); str.push_back ('a' );itoa (100 ,string ,10 );
1 2 3 #include <cstring> strlen (s);strcpy (p,s);
17、智能指针 1.常见的智能指针
auto_ptr(c++11已经将其抛弃)
unique_ptr(两个unique_ptr)不能指向同一个对象,指针间无法值传递
头文件:memory
本身是一个类模板
shared_ptr,多个指针可以指向同一个对象,
头文件:memory
weak_ptr,与shared_ptr共同工作,不具有普通指针的行为,
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 unique_ptr<int > u_i; u_i.reset (new int (3 )); unique_ptr<int > u_i2 (new int (4 )) ;unique_ptr<T,D> u (d) ; int *p_i = u_i2.release (); unique_ptr<string> u_s (new string("abc" )) ; unique_ptr<string> u_s2 = std::move (u_s); u_s2.reset (u_s.release ()); u_s2=nullptr ;int main () { shared_ptr<int > sp (new int (10 )) ; assert (sp.use_count () == 1 ); weak_ptr<int > wp (sp) ; assert (wp.use_count () == 1 ); if (!wp.expired ()) { shared_ptr<int > sp2 = wp.lock (); *sp2 = 100 ; assert (wp.use_count () == 2 ); } assert (wp.use_count () == 1 ); cout << "int:" << *sp << endl; return 0 ; }
18、杂七杂八 1.对象交互
2.enum(枚举)
enum:一种基本数据类型,它可以让数据更简洁,更易读。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 enum day { mon = 1 , twe, wed, };enum Day { sun, twe, wed = 4 , thu, }int main (){ day d1 = sun; }
3.关于指针与数组头大小计算
可以把一个一维数组的头赋值给一个一级指针,但是指针的大小是指针本身,数组的头的大小是数组的大小。
不可以把一个二维数组的头赋值给一个二级指针,二级指针的大小和一级指针大小一致,数组的头的大小是整个二维数组大小。
主要原因可能 是两者大小冲突,而一维数组的由于长度不缺定可以退化到指针。
*但如果我把二级指针写成int (z)[3]的形式,即一个数组指针,这时就可以直接赋值。这时z和*z的值相同,而且z的大小还是一个指针变量的大小。
指针变量大小为8个字节。