(一)基本概念:
1、类与对象:
1 //声明类 2 class Human { 3 4 //... Data members and methods go here 5 6 }; 7 8 //定义对象 9 Human human;
2、通常用class声明类,struct也可以,只不过在信息隐藏机制上有点区别;struct默认是public,而class默认是private;只能在类的成员函数或friend函数中访问类的非公有成员;
3、成员选择符:' . ' 和 ' -> ';
4、成员函数的定义:
两种方式:一种在类内定义,所定义的成员函数都是inline类型的;一种是在类外定义;在类外定义时,要使用 ‘::’ 域解析符,在类外定义成员函数,如果声明时,使用inline关键字,可使在类外定义的成员函数强制变成内联函数;
1 class Person { 2 3 public : 4 void setAge( unsigned n ); 5 unsigned getAge() const; 6 private : 7 unsigned age; 8 9 }; 10 11 //define class method; 12 13 void Person::setAge( unsigned n ){ 14 age = n; 15 } 16 unsigned Person::getAge(){ 17 return age; 18 }
5、效率和健壮性:
(1)通过引用来传递和返回对象:
一般来说,对对象的传递和返回应该使用“引用”,因为这样可以提高效率;
注意:在返回引用类型的对象时,如果是在类内定义的对象,要加上static修饰,否则这个对象对其他函数时不可见的;
1 C& get(){ 2 3 static C c1; //注意static修饰符; 4 c1.set(123); 5 return C1; 6 7 }
(2)const类型参数的对象引用:
1 class C{ 2 3 public: 4 void setName(const string& n){ name = n; } 5 //通过const的修饰,setName()不会修改n的值; 6 //... other public members; 7 8 priavte: 9 string name; 10 11 };
(3)const成员函数:
如果一个成员函数不会直接或间接地改变该函数所属对象的任何数据成员,最好把这个成员函数标记为const;称这样的成员函数为只读函数;它只能调用其他的const成员函数;
例如:int get() const { return num ; }
1 //下面展示const的三种用法: 2 3 class C { 4 5 public : 6 //set()中的const表明它不会修改参数n的值; 7 void set (const string& n) { name = n ; } 8 //前面的const表明谁也不能通过这个引用来修改name的值; 9 //第二个const表明get()不会修改name的值; 10 const string& get() const { return name ; } 11 private: 12 string name; 13 14 };
(二)构造函数与析构函数:
1、构造函数:主要用来对数据成员进行初始化,并负责在对象创建时需要处理的事务,对类的健壮性有着重要作用;
特点:函数名与类名相同;没有返回类型;自动调用;可重载;行为与其他函数相同;可在类中定义,也可在声明之外定义;
(1)约束对象的创建:
如果定义了非默认的构造函数,而没有定义默认的构造函数,则系统不会提供默认的构造函数;
(2)在类C的构造函数中错误的使用单一的C类型参数; 例如: class C { public : C (C obj); } //红色标注的是错误的;
在拷贝构造函数可以有一个C参数,但那是一个引用; 例如:class C { public : C (C& obj); } //红色标注的是正确的,因为它是一个拷贝构造函数;
2、拷贝构造函数:
(1)在默认情况下,系统会自动生成一个拷贝构造函数,将源对象所有数据成员的值逐一赋值给目标对象相应的数据成员;
两种原型:例如:Person( Person& ); Person( const Person& )
(2)自定义拷贝构造函数:第一个以后的参数都必须有默认值;例如:
Person( const Person& p , bool married = false );
当一个类包含指向动态存储空间指针类型的数据成员,则应为这个类设计拷贝构造函数;
//应当举例说明:::::暂略
通过自定义构造函数可禁止通过传值方式传递和返回类对象:因为传值需要拷贝,把拷贝构造函数设为私有,可禁止传值;
1 class C { 2 3 public : 4 C(); 5 private: 6 C( C& ); //把拷贝构造函数设为私有; 7 8 }; 9 10 void f( C ) { ... } //Call by value 11 12 C g() { ... } //return by value 13 14 int main() 15 { 16 C c1,c2; 17 f(c1); //...Error,可改为 void f(C& obj) { ... } 18 c2 = g(); //....Error,可改为 C& g(){ ... }; 19 }
3、转型构造函数:只有一个参数,用于类型间的转换;例如,类C的转型构造函数可将其他类型的变量转型为类C类型的变量;
注意关键字:explicit;
4、构造函数初始化程序:
1 //在此程序中,对c进行赋值是非法的.... 2 class C { 3 public : 4 c() { 5 x = 0; 6 c = 0; //Error . c is const 7 } 8 private: 9 int x; 10 const int c; 11 };
应改为:这是初始化const成员变量的唯一方法;初始化列表仅在构造函数中有效;可初始化任何数据成员;
1 class C { 2 public : 3 C() : c( 0 ) { x = 0; } 4 private : 5 int x; 6 const int c; 7 };
5、构造函数与操作符new和new[]
当使用动态方式为一个对象分配存储空间时,C++操作符new和new[]比函数malloc和calloc做的更好, 因为它们会调用相应的构造函数;
6、析构函数:
发生在如下情况:一是以某个类作为数据类型的变量超出了其作用范围;一是用delete操作符删除动态分配的对象;
例如:~C(); //不带参数,不能被重载;
7、构造函数与析构函数的调用顺序:
构造函数:先调用父类的构造函数,然后才是子类的构造函数;
析构函数:先调用子类的析构函数,然后才是父类的析构函数;
(三)类数据成员与类成员函数:
1、使用 static 修饰, 属于整个类,可被某个对象调用,也可被类调用(被类调用时,使用 :: 操作符);修饰词一般只在声明时使用;例如:
1 class C{ 2 3 private : 4 static int x ; 5 6 }; 7 8 int C :: x = 0; //无需加static
2、在成员函数内部定义static变量:
该类的所有的对象在调用这个成员函数时,将共享这个变量;
(四)指向对象的指针(->):
1、用途:一是作为参数传递给函数,或是通过函数返回,一是使用操作符new和new[]动态创建对象,然后返回一个指向该对象的指针;
2、常量指针this:在成员函数内部可以用this来访问与成员函数的调用相关联的对象;
例如:void setID (const string& id) { this->id = id ; }
//// //C++学习笔记 ////