C++基础知识-inline、const、mutable、this、static
一、在类定义中实现成员函数inline
类内的成员函实现其实也叫作类内的成员函数定义。
这种直接在类的定义中实现的函数,会被当做inline内联函数来处理。
二、成员函数末尾的const
const:常量,在成员函数后面增加一个const。不但需要在成员函数声明的中增加const,也要在成员函数定义中增加const。
作用:告诉系统,这个成员函数不会修改对象里面任何变量的值等等,也就是说,这个成员函数不会修改MyTime类的任何状态。
函数末尾增加一个const称为常量成员函数。
三、mutable
mutable,不稳定,容易被改变,mutable的引入是为了突破const的限制
一旦一个成员变量被mutable修饰了,就表示这个成员变量永远处于可以被修改的状态,即便是在const结尾的成员函数中也可以被修改。
const成员函数,则不管是const对象,还是非const对象,都可以调用const成员函数
而非const成员函数不能被const对象调用。
四、返回自身对象的引用,this
如何理解这个this?在调用成员函数时,编译器负责将这个对象的地址(&mytime)传递给这个成员函数中的一个隐藏的this形参。
在系统角度看来,任何对类成员的访问都被看做是通过this做隐式调用的。
(1)this指针只能在成员函数中使用,全局函数,静态函数不能使用this指针
(2)在普通函数中,this是指向非const对象的const指针(类型为MyTime,那么this就是MyTime *const this),表示this只能指向当前MyTime对象。
(3)在const成员函数中,this指针是一个指向const对象的const指针(类型为MyTime,this就是const MyTime *const this 类型的指针)
MyTime mytime; mytime.addMinute(10); mytime.addSecond(0).addMinute(20);
五、static成员
有属于整个类的成员变量,这种成员变量就是static成员变量(静态成员变量)。
特点:不属于某个对象,属于整个类,我们一旦在某个对象中修改了这个成员变量的值,在其他对象中可以看到修改后的结果。
这种成员变量只有一个副本,对于这种成员变量的引用,我们用的是类名::成员变量名。
成员函数前面也可以加static构成静态成员函数,属于整个类的成员函数,调用的时候用类名::成员函数名。
如何定义静态成员变量:我们一般在某个.cpp源文件的开头来定义这个静态成员变量。这样就能保证在调用任何函数之前这个静态成员变量已经被初始化。
本节工程案例:
#include <iostream> #include "head.h" using namespace std; static int g_abc = 15; // 保存在静态存储区 void func() { static int abc = 5; // 局部静态变量 abc = 8; // 下次执行时static int abc = 5;这条语句不执行,每次执行完保存最后修改的abc的值 } // 静态成员变量定义 int MyTime::static_value = 15; // 可以不初始化,系统默认给0,定义时不需要static int main() { MyTime mytime; mytime.addMinute(10); mytime.addSecond(0).addMinute(20); MyTime mytime1; mytime1.Minute = 15; MyTime mytime2; mytime2.Minute = 20; cout << mytime1.Minute << endl; cout << mytime2.Minute << endl; return 0; } // MyTime.h文件 #ifndef __MYTIME__ #define __MYTIME__ class MyTime { public: // 成员变量 int Hour; int Minute; int Second; mutable int testValue; private: // 成员变量 int Millsecond; public: //成员函数 void initMillTime(int tmpMillTime); // 构造函数 explicit Time(int tmphour,int tmpminute,int tmpsecond); Time(int tmphour,int tmpminute); explicit Time(int tmphour); explicit Time(); static int static_value; // 静态成员变量声明 public: void addhour(int tmphour) const; //{ //Hour += tmphour; //} MyTime& addMinute(int tmpMinute); MyTime& addSecond(int tmpSecond); } #endif // MyTime.cpp文件 #include "head.h" void MyTime::initMillTime(int tmpMillTime) { Millsecond = tmpMillTime; } // 构造函数 MyTime::Time(int tmphour,int tmpminute,int tmpsecond) { Hour = tmphour; Minute = tmpminute; Second = tmpsecond; } MyTime::Time(int tmphour,int tmpminute) { Hour = tmphour; Minute = tmpminute; } MyTime::Time(int tmphour) { Hour = tmphour; } MyTime::Time() {} void MyTime::addhour(int tmphour) const { // Minute = tmphour; // 不允许修改类对象里面的任何成员 testValue = tmphour; //给要改变的变量前面加一个mutable就可以修改了 } MyTime& MyTime::addMinute(int tmpMinute) { Minute = tmpMinute; return *this; // 返回对象本身 } MyTime& MyTime::addSecond(int Second) { this->Second = Second; return *this; // 返回对象本身 }
六、类内初始化
在C++11离,我么可以为类内成员变量提供一个初始值,则我们在创建对象的时候,这个初始值就用来初始化该成员变量。
七、const成员变量的初始化,在构造函数的初始化列表里进行,不可以通过赋值来初始化。
八、默认构造函数
默认构造函数,即没有参数的构造函数就是默认构造函数。
没有构造函数,这些类对象时如何调用的?这叫做默认初始化,也就是说类通过一个特殊的构造函数来执行默认的初始化过程。
这个特殊的构造函数就叫做“默认的构造函数”。也就是无参的构造函数。
在类定义中,如果没有构造函数的情况下,编译器会为我们隐式的自动定义一个默认的构造函数。称为“合成的默认构造函数”。
一旦我们自己写了一个构造函数,不管这个构造函数带几个参数,编译器就不会为我们创建“合成的默认构造函数”。
九、=default,=delete
=default 编译器能自动为我们生成函数体,一般只能以用于默认的特殊成员函数
十、拷贝构造函数
默认情况下,类对象的拷贝时每个成员变量的逐个拷贝。
如果一个类的构造函数的第一个参数是所属的类类型的引用,如果还有其他额外参数,那么这些额外的参数还都有默认值,则这个构造函数称为拷贝构造函数。
函数默认参数必须放在函数声明中,除非该函数没有函数声明。
(1)拷贝函数第一个参数总是带着const
(2)explicit:拷贝构造函数一般不要声明为explicit
成员函数逐个拷贝的功能因为我们自己定义的拷贝构造函数的存在而丢失了作用。
或者说我们自己的拷贝函数取代了系统默认的每个变量逐个拷贝的行为。
(a)如果我们没有定义一个拷贝构造函数,编译器会为我们定义一个;
(b)如果是编译器给我们合成的拷贝构造函数,这个拷贝构造函数一般也是将参数tmpTime(类对象)的成员逐个拷贝到正在创建的对象中。
每个成员的类型决定了它如何拷贝,比如说成员变量是整型的,那么直接把值拷贝过来;
如果成员变量是类类型,那么会调用这个类的拷贝构造函数来拷贝。
(c)如果自己定义了拷贝构造函数,那么就取代了系统合成的拷贝构造函数,这个时候,你就必须在自己的拷贝构造函数中给类成员变量赋值,以免出现类成员没有被赋值就使用的情况发生。
还有一些情况会发生调用拷贝构造函数的情况:
(1)将一个对象作为实际参数传给一个非引用类型的参数。
(2)从一个函数中返回一个对象的时候。