C++中的构造函数与创设对象的(简单)过程

C++中的构造函数与创建对象的(简单)过程

•构造函数

     –和类名相同
     –没有返回值类型
     –只在建立对象的时候被自动调用一次
     –调用构造函数的主要目的是初始化对象

•一个对象的创建过程:
     –分配内存空间
     –初始化成员变量,如果成员是对象,构造他
     –调用构造函数

默认的空参构造函数

构造函数的使用

•构造函数重载
     –构造函数也是函数,拥有重载的特征
     –重载的构造函数在构造对象时根据参数自动选择

•利用参数默认值简化构造函数
     –构造函数也拥有函数参数默认值的特性
     –使用默认值可以减少构造函数的个数

•构造函数的初始化列表
     –初始化列表可以让构造函数在调用之前进行初始化工作
     –如果类的成员变量是const或引用类型,使用初始化列表是不二选择

•实践中,类的声明和定义是分开的
     –请试着将写的类分成头文件和实现两部分


<pre name="code" class="cpp">//构造方法
#pragma  在做游戏的公司里面初始化的方法有两种风格  一种是init这是本来做苹果转过来的  另外一种是在构造方法里面初始化 (这本来就是做C++的)


#include <iostream>
using namespace std;

//类
class Time{
    //默认是私有的
    int hour;
    int min;
    int sec;
    
    //
    void dida(){
        sec++;
        if (60 == sec) {
            sec = 0;
            min++;
        }
        
        if (60 == min) {
            min = 0;
            hour++;
        }
        
        if (24 == hour) {
            hour = 0;
        }
    }
    
    
    
    
public:
#pragma  构造方法: 没有返回值 ,方法名与类名相同。构造方法在创建对象的时候一定会被动的调用一次。如果我们自己没有写构造方法,编译器会帮我们写一个无参的构造方法
    //构造函数的参数可以给定默认值
    /*
    Time (int h = 0,int m = 0,int s = 0){
        cout << "Time (int h,int m,int s)在构造方法中初始化成员变量" << endl;
        //通常在构造方法里面去初始化成员变量
        hour = h;
        min = m;
        sec = s;
    }
     */
    
#pragma 初始化列表给成员变量初始化
    //构造函数 可以用初始化列表 进行初始化
    //只需要在参数括号后面加单冒号后面的就是初始化列表
    Time (int h = 0,int m = 0,int s = 0):hour(h),min(m),sec(s){
        cout << "初始化列表给成员变量初始化" << endl;
       
    }
    
    
    //重载 构造函数
    /*
    
    Time() {
        hour = 0;
        min = 0;
        sec = 0;
        cout << "创建对象的时候如果没有参数就默认找到这个无参的Time ()构造方法" << endl;
    }
     //如果把这个打开注释 main函数里面Time t2;会出现报错时因为上面的构造函数给定默认值了也可以不传参 所以不知道用哪一个
     */
    
    
    
    //公开的初始化方法
    void init(int h,int m,int s){
        hour = h;
        min = m;
        sec = s;
    }
    
    
    //运行
    void run(){
        while (1) {
            
            show();
            dida();
            //代表一个时间
            time_t cur = time(0);//0是获取当前系统的时间
            //注意理解
            while (cur == time(0)) {
                //死循环1秒钟
            }
        }
    }
    
    //显示
    void show(){
        cout << hour << "时" << min << "分" << sec << "秒" << endl;
    }
  
};

//主函数
int main(int argc, const char * argv[])
{
    
    //创建对象  并把参数传进去给构造函数
    Time t(15,38,27);
    t.show();
    //t.run();//这个函数是死循环   下面的代码不会执行
    
    
#pragma 现在我希望这样也不报错,那该怎么办?
    Time t2;// 一.方法重载  二.有参的构造方法给定参数的默认值
    t2.run();
    
#pragma 在创建对象的时候  有参数的话就找到有参的构造函数。无参数的话就默认找到原来的无参的构造函数。
    return 0;
}



运行结果如下:

初始化列表给成员变量初始化
15时38分27秒
初始化列表给成员变量初始化
0时0分0秒
0时0分1秒
0时0分2秒
0时0分3秒

Program ended with exit code: 9


利用构造函数初始化成员变量的两种方法:

一.直接在构造函数体中初始化

二.用初始化列表

既然两种方法都可以初始化成员变量,那它们之间到底有什么区别呢??

大多数情况下两种都可以,但是极个别情况必须要用初始化列表。它们的区别在于创建对象那个过程调用的时机。

在方法体里面直接赋值初始化的,是当构造函数已经开始调用了的时候。

而实用初始化列表的,是在构造函数调用前初始化



创建对象的过程

1.开辟内存空间

2.初始化成员变量

3.调用构造方法

也就是说构造方法是最后一个才调用的



这第2步首先得到的是垃圾值,接着再在构造函数体内赋值初始化成员变量。

然而利用初始化列表初始化成员变量的那种方法,它的意思是在第2步的时候告诉编译器:你就别给我垃圾值了,我直接利用初始化列表的值,然后再调用构造方法。



什么情况只能用初始化列表??


class Example{
    int x=23451234;//创建对象的时候  这里调用第2步初始化得到的是垃圾值
public:
    Example(){
        x = 100;//初始化
    }
};


/******例如这种情况就必须要使用初始化列表了********/
/*
class Example1{
    int x=23451234;//创建对象的时候  这里调用第2步初始化得到的是垃圾值
    int& r;//这是引用类型在创建的时候必须给它赋值  如果是这样可能得到垃圾值
public:
    Example1(int a){
        x = 100;//初始化
        r = a;
    }
};
*/
class Example1{
    int x=23451234;//创建对象的时候  这里调用第2步初始化得到的是垃圾值
    int& r;//这是引用类型在创建的时候必须给它赋值
public:
    Example1(int a):r(a){ //利用初始化列表给引用初始化
        x = 100;//初始化
#pragma 也就是说如果你的成员变量里面有引用类型的,那么必须使用初始化列表,否则等到构造方法一调用那么一切都晚了
    }
};


class Example2{
    int x=23451234;//创建对象的时候  这里调用第2步初始化得到的是垃圾值
    int& r;//这是引用类型在创建的时候必须给它赋值
    const int i;
    
public:
    Example2(int a):r(a),i(200){ //利用初始化列表给引用初始化
        x = 100;//初始化
        //r = a;
       // i = 300; //const一旦声明就不能改变它的值了
#pragma 也就是说如果你的成员变量里面有引用类型的,那么必须使用初始化列表,否则等到构造方法一调用那么一切都晚了
        //如果成员变量是常量 也需要初始化列表初始化
    }
};

总结:

成员变量里面有引用类型的变量 或者 是const常量类型的变量  那就必须要使用初始化列表来初始化成员变量。