1 this
任何对类成员的直接访问都被看成this的隐式引用,this是一个常量指针 (class *const),不允许改变this中保存的地址。
常量成员函数:在参数列表后面加一个const,表示this是一个指向常量的指针(const class *const this);
不能再一个常量对象上调用普通的成员函数,因为this是一个指向非常量的常量指针,因此无法将常量成员赋给this指针,这时在参数列表之后添加一个const可以解决问题,所以说这个const其实是将this修改为指向常量的常量指针。
2 构造函数
1)构造函数的名字和类名相同
2)构造函数没有返回类型
3)构造函数不能被声明为const类型。
4)创建类的const对象时,直到构造函数完成初始化,对象才能真正取得其常量属性。
3 合成默认构造函数
默认构造函数,不接受任何参数,因此在类中可以定义默认构造函数,但是问题在于若程序定义了其他构造函数的话,那么编译器是否还会生成这个,还是根据编译器而异???。
若程序没有显式的定义构造函数,则编译器会合成一个默认构造函数(合成默认构造函数)。
默认构造函数的初始化类的规则为:
1)如果存在类内的初始值,用它来初始化成员(c++11新标准)
2)否则,默认初始化该成员。
4 合成默认构造函数的风险
合成默认构造函数适合那些简单的类
1)定义在块中的内置类型或复合类型被默认初始化的话,那么它的值是未定义的。
2) 有时候编译器无法为某些情况下生成默认构造函数,如类中包含其他类类型,若类中的类类型没有默认初始化函数,则编译器无法合成默认初始化函数。
5 =default
C++11新标准中,如果需要默认行为,那么可以通过在参数列表后面写上=default来要求编译器生成构造函数。
6 某些类不能依赖于合成的版本(先记者,之后再来补充)
管理动态内存的类。vector string等有完备的资源管理 在类中无需担心其构造和析构,赋值问题。
7 访问权限实现了封装。
class 默认访问权限是private,在第一个访问控制符之前是这样。
struct 默认访问权限是public。
8 封装
所谓封装就是将类的实现的细节隐藏起来,让外界无法直接使用,只能通过某些特定的方式才能访问。
封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是通过外部接口以及特定的访问权限来使用类的成员。
优点:
1 确保用户代码不会无意间破坏封装对象的状态。其实提供访问方式还是可能被修改,但是可以降低风险。
2 被封装的类的具体实现细节可以随时改变,而无须调整用户级别的代码。
9 友元函数
友元声明只能出现在类定义的内部,虽然不受访问控制符的限制但是最好集中定义在第一个控制符之前。
友元函数需要两个声明,一个在函数体中,一个在函数外,这两个最好放在同一个头文件中。
类的外部也需要该函数相应的声明,从而使得该函数可见。
struct X{
friend void f(){/*友元函数可以定义在类的内部*/}
X(){f();} //错误:f还没有被声明
void g();
void h();
};
void X::g(){return f();} //错误:f还没有被声明
void f(); //声明那个定义在X中的函数
void X::h(){return f();} //正确:现在f的声明在作用域中了
10 函数重载
函数重载包括一般的函数在其作用域内,还有就是成员函数。(之前一直以为只有类成员函数才可以,误解了)
11 可变数据类型
即使是在const类也可以被修改,在变量的声明中加入mutable 关键字。一个const成员函数可以改变一个可变成员的值(按理说不可以)。
12 *this
从const成员函数返回*this,之前提过的const 改变了this 的类型,因此需要注意的是需要注意此时返回*this 引用的话返回值的类型。
13 类的作用域
类的定义分两步处理:
首先,编译成员的声明。
直到类全部可见后才编译函数体。
类型名要特殊处理,一般情况下,内层作用域可以重新定义外层作用域中的名字,即使该名字已经在内层已经使用过。但是类型名不可以,所以类型名需要在类开始就定义,这样保证了类内用的一直是同一种类型。