C++面对对象(下)

 讲解大致内容为初始化列表,explicit关键字,static(静态)成员


目录

初始化列表与函数构造体赋值

函数构造体赋值

初始化列表

使用初始化列表的初始化顺序

使用初始化列表的优点

explicit关键字

static成员(静态)

概念


初始化列表与函数构造体赋值

函数构造体赋值

在创建对象时,编译器会通过调用构造函数,给对象中的各个成员变量一个合适的初始值:

class A
{
    public:
    // 构造函数
    Date(int X = 0, int Y = 0, int Z = 0)
    {
        _X = X;
        _Y = Y;
        _Z = Z;
    }
private:
    int _X;
    int _Y;
    int _Z;
};

注:上述的函数构造体赋值可以进行多次赋值,而下面我们要讲的初始化列表

初始化列表

一、每个成员变量在初始化列表中只能出现一次  因为初始化只能进行一次,所以同一个成员变量在初始化列表中不能多次出现

class A
{
    public:
    // 构造函数
    Date(int X = 0, int Y = 0, int Z = 0)
        :_X(X)
        ,_Y(Y)
        ,_Z(Z)
    {}
private:
    int _X;
    int _Y;
    int _Z;
};

二、类中包含以下成员,必须放在初始化列表进行初始化:

1.引用成员变量  引用类型的变量在定义时就必须给其一个初始值,所以引用成员变量必须使用初始化列表对其进行初始化。

class A
{
    public:
    // 构造函数
    Date(int X = 0, int Y = 0, int Z = 0)
        :_X(X)
        ,_Y(Y)
        ,_Z(Z)
    {}
private:
​
    int& _b = 0;// 创建时就初始化
};

2.const成员变量  被const修饰的变量也必须在定义时就给其一个初始值,也必须使用初始化列表进行初始化。

class A
{
    public:
    // 构造函数
    Date(int X = 0, int Y = 0, int Z = 0)
        :_X(X)
        ,_Y(Y)
        ,_Z(Z)
    {}
private:
    
    const int a = 10;//correct 创建时就初始化
};
 
 

3.自定义类型成员(该类没有默认构造函数)  如果一个类没有默认构造函数,那么我们在实例化该类对象时就需要传参对其进行初始化,所以实例化没有默认构造函数的类对象必须使用初始化列表对其进行初始化

class B
{
    public:
    // 没有默认构造
    Date(int Big)
      :_Big(Big);
    {}
private:
    int _Big;
};
​
class A
{
    public:
    // 构造函数
    Date(int A = 0)
        :_Big(A)
    {}
private:
    int _A;
    B _Big;
};

 在这里再声明一下,默认构造函数是指不用传参就可以调用的构造函数:

 1.我们不写,编译器自动生成的构造函数。  2.无参的构造函数。  3.全缺省的构造函数。

使用初始化列表的初始化顺序

举个例子:

class A
{
    public:
    // 构造函数
    Date(int X = 0, int Y = 0, int Z = 0)
        :_X(X)
        ,_Y(Y)
        ,_Z(Z)
    {}
private:
    //初始化列表的初始化顺序
    int _X;//1
    int _Y;//2
    int _Z;//3
};

注:初始化列表的初始化顺序为按照你在private的定义从上到下初始化

使用初始化列表的优点

 因为初始化列表实际上就是当你实例化一个对象时,该对象的成员变量定义的地方,所以无论你是否使用初始化列表,都会走这么一个过程(成员变量需要定义出来)。 严格来说:  1.对于内置类型,使用初始化列表和在构造函数体内进行初始化实际上是没有差别的,其差别就类似于如下

1.对于内置类型,使用初始化列表和在构造函数体内进行初始化实际上是没有差别的

2.对于自定义类型,使用初始化列表可以提高代码的效率

explicit关键字

使用这个关键字explicit来修饰构造函数后就不可以使用单参数构造函数的隐式转换

class A
{
public:
    // 构造函数
    Date(int X = 0)
    _X = X;
    {}
    Print()
    {
        cout<< _X <<endl;
    }
private:
    int _X;
};
int main()
{
    A a1 = 100;
    return 0;
}
 
 

所以在早期的编译器中,当编译器遇到A a1 = 100这句代码时,会先构造一个临时对象,再用临时对象拷贝构造a1;但是现在的编译器已经做了优化,当遇到A a1 = 100这句代码时,这就叫做隐式类型转换

static成员(静态)

概念

 声明为static的类成员称为类的静态成员。用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化,它在静态区(内存模型中)。

静态成员它是类中所有成员共享,不属于具体的一个类。

class A
{
private:
    static int _a;
};
int main()
{
    cout << sizeof(A) << endl;
    return 0;
}

它输出的大小为1,因为它是静态成员_a(在静态区),属于整个类。所以计算类的大小或者类对象的大小时,静态成员并不计算。

静态成员变量必须在类外定义初始化

class A
{
private:
    static int _a;
};
int main()
{
    cout << sizeof(A) << endl;
    return 0;
}
int A::_A = 0;//定义初始化

访问静态成员变量的方法

class A
{
public:
    static int _a; //静态,属于整个类
};
// 静态成员变量的定义初始化
int A::_a = 0;
int main()
{
    Test test;
    cout << A._a << endl; //1.通过类对象突破类域进行访问
    cout << A()._a << endl; //3.通过匿名对象突破类域进行访问
    cout << A::_a << endl; //2.通过类名突破类域进行访问
    return 0;
}
  • 第一种为:通过类对象突破类域进行访问

  • 第二种为:通过匿名对象突破类域进行访问

  • 第三种为:通过类名突破类域进行访问

静态成员函数是没有this指针

class A
{
public:
    static void Fun()
    {
        cout << _a << endl; //不能访问非静态成员
        cout << _b << endl; //可以
    }
private:
    int _a; //非静态成员
    static int _b; //静态成员
}

注:静态成员和类的普通成员一样,也有public、private和protected这三种访问级别 

注:

1、静态成员函数可以调用非静态成员函数吗?

  • 不可以。因为非静态成员函数的第一个形参默认为this指针,而静态成员函数中没有this指针,故静态成员函数不可调用非静态成员函数。

2、非静态成员函数可以调用静态成员函数吗?

  • 可以。因为静态成员函数和非静态成员函数都在类中,在类中不受访问限定符的限制。

猜你喜欢

转载自blog.csdn.net/qq_45591898/article/details/130755722