1.4 C++ 类
在C++中类由成员构成。成员可以是数据,可以是函数,其中函数成为成员函数。类中的每一个实例都是一个对象。每一个对象包含类中指定的数据成员(除非这些数据成员是static)。如下图所示
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 |
class IntCell
{ public: explicit IntCell( int initvalue= 0); /*所有的单参数的构造函数都必须使用explicit,以避免后台的类型转换。*/ IntCell( const IntCell &rhs); /*复制构造函数*/ ~IntCell(); /*析构函数*/ const IntCell & operator=( const IntCell &rhs); /*operator=函数*/ int read() const; /*常量成员函数*/ void write( int x); private: int *storevalue; }; IntCell::IntCell( int initvalue) { storevalue= new int(initvalue); } IntCell::IntCell( const IntCell &rhs) { storevalue= new int(*rhs.storevalue); } IntCell::~IntCell() { delete storevalue; } const IntCell & IntCell:: operator=( const IntCell &rhs) { if( this!=&rhs) { *storevalue=*rhs.storevalue; } return * this; } int IntCell::read() const { return *storevalue; } void IntCell::write( int x) { *storevalue=x; } |
1、默认参数
IntCell构造函数阐述了默认参数,定义了两个IntCell 构造函数。一个构造函数接受initialValue,另一个是零参数构造函数,后者隐藏。
2、初始化列表
构造函数代码体前的代码。
3、explicit构造函数。
所有的单参数的构造函数都必须是explicit的,以避免后台的类型转换。如下代码:
IntCell obj;
obj=37;
C++拥有宽松的规则,通常,单参数构造函数定义了一个隐式类型转换,该转换创建了一个临时对象,从而使得赋值兼容。
编译器尝试将obj=37;转换成Intcell temp=37; obj=temp;
注意临时对象的构造也可以通过使用单参数构造函数实现。使用explicit意味着单参数构造函数不能用来创建隐式临时对象。
4、常量成员函数
访问函数一般是常量成员函数。修改函数。
1.5 C++ 基础
1.5.1 指针
指针变量是用来存储其他对象地址变量。主要用于声明、动态对象创建、垃圾收集及delete、指针的赋值和比较、访问对象成员。
内存泄漏:当一个通过new来分配地址的对象不再引用时,该对象所占的内存不能释放(直到程序结束)。
1.5.2 参数传递
C++有三种传参方式,如:double avg(const vector<int> &arr,int n, bool &flag);
这里 arr是vector<int> 类型,使用按常量引用调用来传递。n是int类型,通过按值调用来传递。flag 是bool类型,使用引址调用。
1.5.3 引用变量
用于传参。
1.5.4 三大函数:析构函数、复制构造函数和operator=
1、析构函数
在一个对象超出其作用域或执行delete时,就调用析构函数。通常析构函数的唯一任务是释放使用对象时所占有的所有资源。
2、复制构造函数
有一种特殊的构造函数,用于构造新的对象,被初始化为相同类型对象的一个副本,这就是复制构造函数。如:
Intcell b=c,或者Intcell b(c)。
3、operator=函数
应用于两个已经构造的函数,用于复制。
4、重构这三大函数的主要原因
采用默认函数,只能实现浅复制。主要问题出现在其数据成员是指针的类。
默认的构造函数不对指针进行任何操作(一个好的理由就是释放这个指针旧必须删除自身)。默认的复制构造函数和operator=也都不复制指针所指向的对象,而是简单地复制指针的值,这样一来得到两个实例,他们包含的指针都指向同一个对象。这被称为浅复制。
我们期望的是对整个对象克隆的深复制。
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 |
IntCell::IntCell( int initvalue) //构造函数 { storevalue= new int(initvalue); } IntCell::IntCell( const IntCell &rhs) //复制构造函数 { storevalue= new int(*rhs.storevalue); } IntCell::~IntCell() //析构函数 { delete storevalue; } const IntCell & IntCell:: operator=( const IntCell &rhs) //operator= 函数 { if( this!=&rhs) { *storevalue=*rhs.storevalue; } return * this; } |
1
2 3 4 5 6 |
IntCell b(
1);
IntCell c(b); cout << b.read() << "," << c.read() << endl; c.write( 2); cout << b.read() << "," << c.read() << endl; |
1.6 模板
模板包括函数模板和类模板。
函数对象的一个典型例子。
注意,对象同时包含数据和成员函数,一个如传递参数一样传递函数的巧妙方法是:定义一个包含零个数据和一个成员函数的类,然后传递这个类的实例。从效果上看就是,通过将其放在对象中实现了函数的传递。该对象通常称为函数对象。具体代码实现如下:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
template <
typename v1 ,
typename v2>
const v1 &findMax( const vector<v1> &a, v2 isLessThan) { int MaxIndex = 0; for( int i = 0; i < a.size(); i++) if(isLessThan(a[MaxIndex], a[i])) MaxIndex = i; return a[MaxIndex]; } class CaseInsensitiveCompare //重载()操作符 { public: bool operator() ( const string &lhs, const string &rhs) const { return stricmp(lhs.c_str(), rhs.c_str()) < 0; } }; |
1.7 使用矩阵
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 |
//使用矩阵 使用向量的向量 template < typename Object> class maxtrix { public: maxtrix( int rows, int cols): array(rows) { for( int i = 0; i < rows; i++) { array[i].resize(cols); } } const vector<Object> & operator[]( int row) const { return array[row]; } int numrows() const { return array.size(); } int numcols() const { return numrows ? array[ 0].size() : 0; } private: vector<vector<Object> >array; }; |