类默认构造函数可能执行错误的操作

类默认构造函数可能执行错误的操作

今天看C++ Primer中关于构造函数时,第一次了解到合成的默认构造函数可能执行错误的操作的说法(因为每次定义类时都有写默认构造函数的习惯,所以不知道使用合成的默认构造函数或许会带来问题)。

与内置类型或复合类型的局部对象默认初始化情况相似

书中进一步说明如果定义在块中的内置类型或复合类型(比如数组和指针)的对象被默认初始化,则它们的值将是未定义的。该准则同样适用于默认初始化的内置类型成员

测试

这里我定义了一个test1类,内部有4个内置类型包括2个int类型和2个char类型,其中两个内置类型提供类内初始值,同时定义了两个string类型,一个有类内初始值而另一个没有。

class test1 {
private:
    int int_mem1;
    int int_mem2 = 0;
    char char_mem1;
    char char_mem2 = 'b';
    string str_mem1;
    string str_mem2 = "str_mem2";

public:
    void print_self() {
        cout << "int_mem1:" << int_mem1 << endl;
        cout << "int_mem2:" << int_mem2 << endl;
        cout << "char_mem1:" << char_mem1 << endl;
        cout << "char_mem2:" << char_mem2 << endl;
        cout << "str_mem1:" << str_mem1 << endl;
        cout << "str_mem2:" << str_mem2 << endl;
    }
};

作为对比,又定义了test2类,与test2类与test1类的区别仅仅在于后者提供了默认初始化函数(只对没有类内初始值的变量进行初始化)。

class test2 {
private:
    int int_mem1;
    int int_mem2 = 0;
    char char_mem1;
    char char_mem2 = 'b';
    string str_mem1;
    string str_mem2 = "str_mem2";

public:
    test2() :int_mem1(0), char_mem1('b'), str_mem1("str_mem1") {};

public:
    void print_self() {
        cout << "int_mem1:" << int_mem1 << endl;
        cout << "int_mem2:" << int_mem2 << endl;
        cout << "char_mem1:" << char_mem1 << endl;
        cout << "char_mem2:" << char_mem2 << endl;
        cout << "str_mem1:" << str_mem1 << endl;
        cout << "str_mem2:" << str_mem2 << endl;
    }
};

最后又定义了test3类,test3类仅提供了带参数的构造函数

class test3 {
private:
    int int_mem1;
    int int_mem2 = 0;
    char char_mem1;
    char char_mem2 = 'b';
    string str_mem1;
    string str_mem2 = "";

public:
    test3(const int val1, const int val2, const char c1, const char c2, const string &str1, const string& str2) :
        int_mem1(val1), int_mem2(val2), char_mem1(c1), char_mem2(c2), str_mem1(str1), str_mem2(str2) {};

public:
    void print_self() {
        cout << "int_mem1:" << int_mem1 << endl;
        cout << "int_mem2:" << int_mem2 << endl;
        cout << "char_mem1:" << char_mem1 << endl;
        cout << "char_mem2:" << char_mem2 << endl;
        cout << "str_mem1:" << str_mem1 << endl;
        cout << "str_mem2:" << str_mem2 << endl;
    }
};

以下是执行测试的代码,首先我把对test3的定义和接口函数调用部分给屏蔽掉,这一点后面描述。

int main()
{
    //test1
    test1 t1;
    cout << "test1:" << endl;
    t1.print_self();
    cout << "---------------------------------------" << endl;
    //test2
    test2 t2;
    cout << "test2:" << endl;
    t2.print_self();
    cout << "---------------------------------------" << endl;
    /*cout << "test3_1:" << endl;
    test3 t3_1;
    t3_1.print_self();
    cout << "---------------------------------------" << endl;
    cout << "test3_2:" << endl;
    test3 t3_2(0, 0, 'a', 'b', "str_mem1", "str_mem2");
    t3_2.print_self();
    cout << "---------------------------------------" << endl;*/
}
}

以下是test1和test2对象的构造以及接口函数调用的结果:
在这里插入图片描述
可以发现test1输出结果中,int_mem1成员的值为随机值,char_mem1成员的值为空字符。我们可以把类内作用域看作一个块,类成员变量时这个块内的一个局部变量,当该类的对象被创建时,没有类内初始值的内置类型或复合类型成员执行默认初始化,其结果和局部变量执行默认初始化情况一致。
如果我们把test3部分的内容取消注释,编译器会报错:
在这里插入图片描述
我们没有为test3类提供默认构造函数,是因为只要类显示地声明了任何构造函数,编译器都不会提供合成的默认构造函数。因此,这里我们要为test3声明和定义默认构造函数。
修改后的test3如下所示,此时编译器通过。这里定义的默认构造函数与合成的默认构造函数功能一致。

class test3 {
private:
    int int_mem1;
    int int_mem2 = 0;
    char char_mem1;
    char char_mem2 = 'b';
    string str_mem1;
    string str_mem2 = "";

public:
    test3() {};
    test3(const int val1, const int val2, const char c1, const char c2, const string &str1, const string& str2) :
        int_mem1(val1), int_mem2(val2), char_mem1(c1), char_mem2(c2), str_mem1(str1), str_mem2(str2) {};

public:
    void print_self() {
        cout << "int_mem1:" << int_mem1 << endl;
        cout << "int_mem2:" << int_mem2 << endl;
        cout << "char_mem1:" << char_mem1 << endl;
        cout << "char_mem2:" << char_mem2 << endl;
        cout << "str_mem1:" << str_mem1 << endl;
        cout << "str_mem2:" << str_mem2 << endl;
    }
};

以下时代码运行结果:
在这里插入图片描述
同样的,创建t3_1对象会产生值未定义行为,而t3_2调用带参数的构造函数,不会产生这种行为。

总结

使用合成的默认构造函数创建对象时,类内内置类型或复合类型会产生值未定义的行为,进而对后面的模块带来影响,因此我们定义一个类时,最好定义一个默认构造函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值