目录
- 一、细说构造函数
- 1.1初始化列表的引入
- 1.2初始化列表
- 1.2关键字explicit
- 二、static成员
- 2.1static成员的特性
- 2.2题目:实现一个类,计算程序中创建出了多少个类对象
- 2.3题目:设计一个类 只能再栈上或者堆上创建
一、细说构造函数
1.1初始化列表的引入
我们都知道构造函数的作用是在创建对象的时候给对象的成员属性赋值。
那么下面的场景可以用构造函数进行赋值吗?
#include<iostream>
using namespace std;
class example1
{
public:
//可以这么写吗? 编译器能通过吗?
example1(int i, int j)
{
x = i;
j = y;
}
private:
const int x;
int& y;
};
int main()
{
return 0;
}
答案是不可以的。编译器也不支持这么胡搞。
首先要知道为什么不可以这么写。
为了解决上面不能使用构造函数来初始化的场景,所以就引入了初始化列表这个概念。可以通过初始化列表来完成初始化。比如:
1.2初始化列表
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
注:
- 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
- 类中包含以下成员,必须放在初始化列表位置进行初始化:引用成员变量、 const成员变量、自定义类型成员(且该类没有默认构造函数时)
怎么理解上面被加粗的这段话呢?
之前在C++类和对象(上)说过默认构造函数会对内置类型不做处理对自定义类型会调用其默认构造函数。这句话准确的来讲是在初始化列表会调用自定义类型的默认构造函数。如图:
那如果example2没有默认构造函数呢?我的意思是你重载了一个有参构造函数、或者说你重载了两个有参构造函数,此时默认构造函数就失效了,而编译器又不知道你调用的有参构造函数的参数是多少,所以编译器不能帮你调用有参构造函数,所以就会报错。
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。这个比较坑,稍不留神都不知道自己错在哪里。比如:
初始化列表顺序是从_arr开始,而_arr需要使用_capacity来初始化,慢慢的开始离谱了。
1.2关键字explicit
这个是4/6级词汇。顺带复习一下。
explicit:adj 清楚的、明确的、易于理解的。
explicitness:n 直言不讳、明确性
explicitly:adv 清楚明确地
在了解explicit这个关键字的作用之前先看看这个代码:
这么写为什么不会报错呢?这个代码不符合我们对类的常规认识呀。
其实这里发生了隐式类型转换。具体如下:
这里再补充一个奇葩的写法。如下:
说明如下:
那如果你不想发生隐式类型转换怎么办呢?就需要用到关键字explicit 这个英文含义是直接了当的,不需要隐式类型转换这个含糊不清的东西。比如:
二、static成员
2.1static成员的特性
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化。
特点:
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
- 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
- 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员也是类的成员,受public、protected、private 访问限定符的限制
2.2题目:实现一个类,计算程序中创建出了多少个类对象
代码:
#include<iostream>
using namespace std;
class example
{
public:
example()
{
num++;
}
static int GetNum()
{
return num;
}
private:
static int num;
};
int example::num = 0;
void test()
{
for (int j = 0; j < 10; j++)
{
example ex;
}
}
int main()
{
for (int i = 0; i < 10; i++)
{
example ex;
}
test();
cout << example::GetNum() << endl;
return 0;
}
**补充:**非静态成员函数可以调用静态成员函数,而静态成员函数不可以调用非静态成员函数。
为什么呢?解释如下:
刚刚上面说过了静态成员函数不能访问非静态成员变量。如果一个非静态成员函数A进行了对非静态成员函数的访问,那么此时你用静态成员函数B再去访问非静态成员函数A不就相当于完成了对非静态成员的访问了?那么就矛盾了。
2.3题目:设计一个类 只能再栈上或者堆上创建
#include<iostream>
using namespace std;
class example
{
public:
static example GetObjectInStack()
{
example ex;
return ex;
}
static example* GetObjectInHeap()
{
return new example;
}
private:
example()
{}
};
int main()
{
example ex1 = example::GetObjectInStack();
example* ex2 = example::GetObjectInHeap();
return 0;
}