构造函数拓展

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/dxd_123456/article/details/78021032

1、默认构造函数
如果类中没有定义任何构造函数,编译器会自动生成一个无参构造函数,没有做任何事情, 如果写了构造函数,编译器将不再提供默认的无参构造函数,如果还还想进行无参构造,需要显示定义无参构造函数
如果没有定义拷贝构造函数,编译器会自动生成一个拷贝构造函数,会做普通类型数据的复制。
还会生成一个默认的 析构函数。

class Test7_2
{
    Test7_2() {}
    Test7_2(const Test7_2 &obj) {}

    ~Test7_2(){};
};

如果没有定义拷贝构造函数,会默认生成一个拷贝函数,但如果我们不想被拷贝呢?(随意的拷贝构造函数可能会出现访问非法内存的问题,下文会讲到)怎么达到这一目的呢?
很简单,我们只需要将拷贝构造写成私有的函数,只需声明,不需要实现

private:
    Test8_3(const Test8_3 &ibj);

这样就可以达到这一目的了。

2、构造函数的一些规则:
1)当类中没有定义任何一个构造函数时,c++编译器会提供默认无参构造函数和默认拷贝构造函数
2)当类中定义了拷贝构造函数时,c++编译器不会提供无参数构造函数
3)当类中定义了任意的非拷贝构造函数(即:当类中提供了有参构造函数或无参构造函数),c++编译器不会提供默认无参构造函数
4 )默认拷贝构造函数成员变量简单赋值
只要你写了构造函数,那么你必须用。
总结:
1)构造函数是C++中用于初始化对象状态的特殊函数
2)构造函数在对象创建时自动被调用
3)构造函数和普通成员函数都遵循重载规则
4)拷贝构造函数是对象正确初始化的重要保证
5)必要的时候,必须手工编写拷贝构造函数

3、对象初始化列表(多个对象构造和析构)
对象初始化列表出现原因
1)必须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

2)类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值,当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。

class Test9_1
{
public:
    Test9_1 (int a)
    {
        m_a = a;
        printf ("9_1 1111111111111111111构造函数....a: %d\n", a);
    }

    // 析构的顺序和构造的顺序相反,先构造的后析构
    ~Test9_1()
    {
        printf ("9_1 1111111111111111111析构函数....a: %d\n", m_a);
    }
private:
    int m_a;
};

int main()
{

    // Test9_1 a;

    return 0;
}

类中有了构造函数以后,就没有默认的无参构造
所以这样的函数中我们无法同过Test9_1 a来创造一个对象
这时对象初始化列表就可以解决一个类中有另一个没有无参构造的类的对象的初始化


class Test9_2
{
// 对象初始化列表,在构造函数后面加:,后面加上要初始化的对象
// 对象初始化列表要比当前类的构造函数先执行
// 对象的初始化先后顺序和 在对象初始化列表 的顺序无关,和在类中的声明先后顺序有关 
public: 
    Test9_2():m_a(10), m_b(20), m_c(30), m_ca(100)
    {

        printf ("9_2 222222222222构造函数....\n");
    }

    ~Test9_2()
    {
        printf ("9_2 222222222222构造函数....a: %d\n", m_ca);
    }
private:
    Test9_1 m_b;
    Test9_1 m_c;
    Test9_1 m_a;

    const int m_ca;
};

加了这样一个初始化列表后我们就可以通过Test9_2 t对没有默认构造函数的类成员初始化。

4、构造函数和析构函数的调用顺序
1)当类中有成员变量是其它类的对象时,首先调用成员变量的构造函数,调用顺序与声明顺序相同;之后调用自身类的构造函数
2)析构函数的调用顺序与对应的构造函数调用顺序相反

5、构造函数中调用构造函数

class Test10_1
{
//构造函数中调用构造函数 不会达到预期的效果的
public:
    Test10_1(int a, int b)
    {
        m_a = a;
        m_b = b;

        Test10_1(a, b, 30);  // 匿名对象、临时对象
    }

    Test10_1 (int a, int b, int c)
    {
        m_a = a;
        m_b = b;
        m_c = c;
    }

    ~Test10_1()
    {
        printf ("析构*******a = %d, b = %d, c = %d\n", m_a, m_b, m_c);
    }
    void print ()
    {
        printf ("a = %d, b = %d, c = %d\n", m_a, m_b, m_c);
    }
private:
    int m_a;
    int m_b;
    int m_c;
};

int main10_1()
{
    Test10_1 a(10,20);
    a.print();

    printf ("--------------------------------\n");

    return 0;
}

在这个函数执行后我们发现,并不能打印出c的值,所以在构造函数中构造并不能达到预期的目的。最终的结果还是由提供的参数决定。

猜你喜欢

转载自blog.csdn.net/dxd_123456/article/details/78021032
今日推荐