缺省参数

  1. 半缺省参数必须从右往左依次给出,不能间隔着给
  2. 缺省参数在函数声明的时候给出,不能声明定义同时给
  3. 缺省值必须是常量或者全局变量

引用

  1. 在使用引用时,权限可以平移和缩小,不能放大
  2. 引用定义时必须初始化
  3. 引用一旦引用一个实体就不能引用其他实体
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
double d = 2.234;
//类型转换,会生成一份临时拷贝,临时拷贝具有常性
int i = d;
int& i = d;//错误!!!!!
const int &i = d; //临时拷贝具有常性

//表达式也会产生临时变量
int x= 0, y = 1;
const int &i = x + y;//必须要加const
return 0;
}

内联函数

用inline修饰的函数,inline只是一种建议,比较长的函数、递归函数等就算被定义为inline也会被编译器忽略

在调用内联函数的地方进行展开,不需要建立函数栈帧,提升程序运行效率

this指针

  1. this指针被const修饰不能被修改,但是this指针指向的内容可以被修改
  2. 只能在“成员函数”的内部使用
  3. this指针可以在类里面被引用,但是不能在函数形参里面定义,这个编译器会自动生成

练练手

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}

答案:C

在 p->Print() 这一步,可能会觉得是访问了空指针,但是实际上只是把 this 指针赋为空,但是 Print 函数是直接打印的,并没有对 this 指针进行访问,所以不会运行崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
   void PrintA()
  {
       cout<<_a<<endl;
  }
private:
int _a;
};
int main()
{
   A* p = nullptr;
   p->PrintA();
   return 0;
}

答案:B

因为打印的是_a,实际上就是this->_a,所以对this指针进行了访问,导致运行崩溃

默认成员函数

构造函数

  1. 构造函数不是开空间创造对象,而是初始化
  2. 函数名和类名相同
  3. 无返回值,不需要写void
  4. 对象实例化的时候编译器自动调用构造函数
  5. 构造函数可以重载
  6. 编译器自动生成的构造函数,对于内置类型成员变量(int, char, double...)不做处理,对于自定义类型成员变量(class, struct,...)会调用它的无参构造
  7. 如果类中没有显示定义构造函数,编译器会自动生成一个无参的构造函数,一旦用户显示定义编译器将不再生成

析构函数

  1. 析构函数不是对对象本身的销毁,而是完成对象中资源清理工作
  2. 函数名是在类名前面加上~
  3. 在对象声明周期结束的时候自动调用
  4. 析构函数不能重载

拷贝构造

  1. 参数只有一个且必须是类类型对象的引用,使用传值的方式会引发无穷递归,正确形式:Date (const Date& d)
  2. 若未显示定义,则编译器会默认生成,但是只完成字节序的拷贝,即浅拷贝
  3. 如果类中没有涉及资源申请的时候,写不写拷贝构造都可以;但是如果涉及到资源申请,就必须写拷贝构造,否则会出现两个不同的对象指向同一块空间

赋值运算符重载

  1. 函数名是operate后面加需要重载的运算符
  2. ".* " "::" "sizeof" "?:" "." 这5个运算符不能重载
  3. 赋值运算符重载格式:
    • 参数类型:const T&
    • 返回值类型:T&,有返回值是为了连续赋值
    • 检测是否是自己给自己赋值
    • 返回*this,要符合连续赋值的定义
1
2
3
4
5
6
7
8
9
10
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
  1. 赋值运算符重载只能重载成类的成员函数,不能重载成全局函数
  2. 同拷贝构造一样,默认的赋值运算符重载只完成浅拷贝

const成员

const修饰的“成员函数”成为const成员函数,实际上修饰的是this指针,表明在该成员函数中不能对类中的任何成员进行修改

初始化列表

以一个冒号开始,接着是以一个逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或者表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
class Date
{
public:
Date(int year, int month, int day)    
: _year(year)
   , _month(month)
   , _day(day)
{}
private:
int _year;
int _month;
int _day;
};
  1. 每个成员变量在初始化列表中只能出现一次,初始化只能初始化一次
  2. 类中包含以下成员,必须放在初始化列表中初始化
    • 引用成员变量
    • const成员变量
    • 自定义类型成员(且该类没有默认构造函数时)
  3. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中初始化的顺序无关