【C++】构造函数的初始化列表、explicit关键字、static(静态)成员

目录

一、初始化列表

二、explicit关键字

三、static成员

1、定义

2、特性


一、初始化列表

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

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成员变量(常量只能初始化不能赋值)
  • 类类型成员(该类没有默认构造函数,使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化)
class A
{
public:
    A(int a):_a(a)
    {}

private:
    int _a;
};

class B
{
public:
    B(int a, int ref):_aobj(a),_ref(ref),_n(10)
    {}

private:
    A _aobj; // 没有默认构造函数
    int& _ref; // 引用
    const int _n; // const
};

3)尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

class Time
{
public:
    Time(int hour = 0):_hour(hour)
    {
        cout << "Time()" << endl;
    }

private:
    int _hour;
};

class Date
{
public:
    Date(int day)
    {}
private:
    int _day;
    Time _t;
};

int main()
{
    Date d(1);
}

4)成员变量是按照他们在类中出现的顺序进行初始化的,而不是按照他们在初始化列表出现的顺序初始化的

class foo
{
public:
    foo(int x):i(x), j(i){}; // ok, 先初始化i,后初始化j
private:
    int i ;
    int j ;
};

再对比下面的代码:

class foo
{
public:
    foo(int x):j(x), i(j){} // i值未定义
private:
    int i ;
    int j ;
};

这里i的值是未定义的因为虽然j在初始化列表里面出现在i前面,但是i先于j定义,所以先初始化i,而i由j初始化,此时j尚未初始化,所以导致i的值未定义。一个好的习惯是,按照成员定义的顺序进行初始化。


二、explicit关键字

C++中的explicit关键字用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式).

在C++中, 如果的构造函数只有一个参数时, 那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象.

class Date
{
public:
    Date(int year):_year(year)
    {}
    explicit Date(int year):_year(year)
    {}
private:
    int _year;
    int _month:
    int _day;
};

void TestDate()
{
    Date d1(2018);

    // 用一个整形变量给日期类型对象赋值
    // 实际编译器背后会用2019构造一个无名对象,最后用无名对象给d1对象进行赋值
    d1 = 2019;
}

上述代码可读性不是很好,用explicit修饰构造函数,将会禁止单参构造函数的隐式转换


三、static成员

1、定义

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化。

class A
{
public:
    A() {++_scount;}
    A(const A& t) {++_scount;}
     // 在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数
    static int GetACount() { return _scount;}
   
private:
    static int _scount;
};

// 静态成员必须在定义类的文件外对静态成员变量进行初始化,否则会编译出错。
int A::_scount = 0;

void TestA()
{
    cout<<A::GetACount()<<endl;
    A a1, a2;
    A a3(a1);
    cout<<A::GetACount()<<endl;
}

2、特性

1)静态成员为所有类对象所共享,不属于某个具体的实例

2)静态数据成员在定义或说明时前面加关键字static初始化在类体外进行,而前面不加static,(这点需要注意)以免与一般静态变量或对象相混淆。

静态数据成员初始化的格式如下:

<数据类型> <类名>::<静态数据成员名>=<值>

(初始化时使用作用域运算符来标明它所属类,因此,静态数据成员是类的成员,而不是对象的成员。)

3)类静态成员访问有两种方法:①类名::静态成员;②对象.静态成员

4)静态成员函数没有隐藏的this指针不能访问任何非静态成员,也不能调用非静态成员函数。

5)静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

6)非静态成员函数可以访问静态数据成员。

猜你喜欢

转载自blog.csdn.net/Jacky_Feng/article/details/109473237
今日推荐