现在除了之前我们讲的构造函数来初始化对象,现在有多了一个初始化列表。
初始化列表我们会认为是成员变量定义的地方
这句话很绕,慢慢往下看。
对于对象而言。成员变量定义的地方又是什么意思?
class A
{
public:
private:
//这是声明
int _a1;
int _a2;
};
int main()
{
//这是定义
Date A;
return 0;
}
但这是对对象整体的定义。每个成员什么时候定义呢?
对象整体定义,每个成员不就定义了吗?道理是这样,但是这样行不通,容易走出歪路子。
class A
{
public:
private:
//这是声明
int _a1;
int _a2;
const int _x;
};
int main()
{
//这是定义
Date A;
return 0;
}
加了就报错,提示没有合适的构造函数可用,为什么?
const int _x;
const变量有什么区别?它必须在定义的位置初始化,因为它只有一次初始化的机会,后面就不能改了。
所以const变量必须要处理,后面就没机会了,那在什么地方处理?
1,c++11支持缺省值,在声明的地方给个缺省值就可以了。
2.c++11之前,怎么解决?
必须给每个成员变量找一个定义的位置,不然像const这样的成员不好出理。
所以构造函数就增加了初始化列表
冒号开始,逗号分割
class A
{
public:
A()
:_x(1)
{
_a1++;
}
private:
int _a1=1;
int _a2=1;
const int _x;
};
int main()
{
A aa;
return 0;
}
1、哪个对象调用构造函数,初始化列表是它所有成员变量定义的位置
2、不管是否显示在初始化列表写,那么编译器每个变量都会初始化列表定义初始化
缺省值是没给的时候才用它
看下面的代码结果是多少。
class A
{
public:
A()
:_x(1)
,_a2(2)
{
_a1++;
_a2--;
}
private:
int _a1=1;
int _a2=1;
const int _x;
};
int main()
{
A aa;
return 0;
}
c++规定有三个东西必须在初始化列表规定。
1.const成员变量
2.引用成员变量
3.自定义类型成员(且该类没有默认构造函数时)
class B
{
public:
B(int b)
:_b(0)
{
cout << "B()" << endl;
}
private:
int _b;
};
class A
{
public:
A()
:_x(1)
, _ref(_a1)
, _bb(0)
{
_a1++;
_a2--;
}
private:
int _a1 = 1; // 声明
int _a2 = 2;
const int _x;
int& _ref;
B _bb;//编译器对内置类型不做处理,如果有缺省值那就有缺省值
//默认生成的构造函数对内置类型不做处理,对于内置类型就调用它的默认构造
//但是它只能调用默认构造,就是不传参数的就可以用的构造函数
};
所有的成员能在初始化列表初始化最好就在初始化列表初始化
class A
{
public:
A(int a)
:_a1(a)
,_a2(_a1)
{}
void Print() {
cout<<_a1<<" "<<_a2<<endl;
}
private:
int _a2;
int _a1;
};
int main() {
A aa(1);
aa.Print();
}
A. 输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机
class A
{
public:
A(int a)
:_a1(a)
{
}
A(const A& a)
{
}
private:
int _a1;
int _a2;
};
A aa1(1)//直接调用构造函数
A aa2=1 // 隐式类型转换 构造+拷贝+优化->构造
1是整型变量怎么赋值给aa2,这里是发生了类型转换,首先用1去构造一个临时对象,然后再拷贝给aa2
如果不行让它发生类型转换,就加上关键字explicit
class A
{
public:
explicit A(int a)
:_a1(a)
{
}
A(const A& a)
{
}
private:
int _a1;
int _a2;
};
实现一个类,计算程序中创建了多少个类对象
class A
{
public:
A(int a = 0)
{
}
A(const A& aa)
{
}
};
void func(A a)
{}
int main()
{
A aa1;
A aa2(aa1);
func(aa1);
A aa3 = 1;
}
因为要创建类对象,就必须要调用构造函数或者拷贝构造,我们可以设定一个全局变量进行计数。
using std::cout;
using std::endl;
int count =0;
class A
{
public:
A(int a = 0)
{
count++;
}
A(const A& aa)
{
count++;
}
};
void func(A a)
{}
int main()
{
A aa1;
A aa2(aa1);
func(aa1);
A aa3 = 1;
cout << count << endl;
}
但是这里有一个不好的地方,count是全局变量,可以随意修改。
这里可以把count定义在类里面,并且用static修饰,表示它是静态类成员,它不属于某个类对象,它属于所有对象,它是属于整个类的。
必须在类外面。
class A
{
public:
A(int a = 0)
{
count++;
}
A(const A& aa)
{
count++;
}
private:
static int count;//不属于某个对象,所于所有对象,属于整个类
// 声明
};
int A::count=0; // 初始化
class A
{
public:
A(int a = 0)
{
count++;
}
A(const A& aa)
{
count++;
}
int GetCount()
{
return count;
}
private:
static int count;//不属于某个对象,所于所有对象,属于整个类
// 声明
};
int A::count=0; // 初始化
int main()
{
A aa1;
cout << aa1.GetCount() << endl;
return 0;
}
为了调用GetCount 这个函数而特意创建一个类,这也太挫了吧,static也可以修饰函数,表示静态成员函数。
class A
{
public:
A(int a = 0)
{
count++;
}
A(const A& aa)
{
count++;
}
static int GetCount()
{
return count;
}
private:
static int count;//不属于某个对象,所于所有对象,属于整个类
// 声明
};
int A::count=0; // 初始化
int main()
{
A aa2;
A aa3;
cout << A::GetCount() << endl;
cout << aa2.count << endl;
cout << aa3.count << endl;
return 0;
}
静态成员函数 – 没有this指针
这也就意味着,静态成员函数不能访问非静态成员变量。
问题
A aa4[10]调用了多少次构造函数?
void func1(A aa)
{
}
void func2(const A& aa)
{
}
int main()
{
A aa1 = 1; // 构造+拷贝构造 -》 优化为直接构造
func1(aa1); // 无优化
func1(2); // 构造+拷贝构造 -》 优化为直接构造
func1(A(3)); // 构造+拷贝构造 -》 优化为直接构造
cout << "----------------------------------" << endl;
func2(aa1); // 无优化
func2(2); // 无优化
func2(A(3)); // 无优化
return 0;
}
判断下面哪种方式更加高效?
直接看结果
第一种
第二种
显而易见,第二种多了一次调用构造函数和赋值运算符重载。
为什么函数返回对象时尽量返回匿名对象我就不说了,因为我的vs2022编译器它自己帮我优化了。
1.举个例子
A& ref=1;//报错
const A& ref=1;//编译通过
为什么第一个代码报错,而第二个代码没有报错?
首先还是回到之前讲的这里会发生类型转换,而类型转换的时候产生了临时对象,而临时对象具有常性,所以必须用const接受。
2.匿名对象
void Func4( const A& a)
{
}
int main()
{
A aa2;
aa2 = Func3();
Func4(A(1));
return 0;
}
不用const接收参数会报错,因为匿名对象也具有常性。
所以尽量使用const&传参