c++类中的临时对象

1. c++临时对象的引入

直接主题,上代码,

#include 
class cls
{
public:
    int a;
    cls(int i)
    {
        a = i;
    }

    cls()
    {
        cls(0);
    }

    void show()
    {
        std::cout << "a = " << a << std::endl;
    }
};

int main(void)
{
    cls c;
    c.show();
    return 0;
}

程序想要实现的功能很简单:定义对象c的时候会编译器会去调用无参构造函数cls(),在cls()中以0作为参数去调用有参构造函数cls(int i),达到将成员变量a设置为0的目的。这是c++代码复用的思想,挺好,看运行结果:
这里写图片描述
显然,打印出来的对象c的成员变量a并没有得到初始化。为什么?这就是临时对象捣的鬼。

2. 临时对象

在c++中,直接调用(代码上手动去调用而非编译器自己调用)构造函数将会产生一个临时对象,写几句代码验证临时对象的存在:

class cls
{
public:
    int a;
    cls(int i)
    {
        a = i;
        std::cout << "cls(int i)" << std::endl;
    }

    cls()
    {
        a = 0;
        std::cout << "cls()" << std::endl;
    }

    cls(const cls& m)   //拷贝构造函数
    {
        std::cout << "cls(const cls& m)" << std::endl;
    }

    void show()
    {
        std::cout << "a = " << a << std::endl;
    }

    ~cls()
    {
        std::cout << "~cls()" << std::endl;
    }
};

int main(void)
{
    cls(5).show();          //手动调用带参构造函数

    return 0;
}

运行结果:
c++类中的临时对象_第1张图片

还能通过cls(5)去调用成员函数:

cls(5).show();

运行结果:
这里写图片描述

show()的调用便是通过临时对象,临时对象没有对象名,它的生命周期只有一条语句(手动调用构造函数)的时间,作用域也只在这条语句间。
注意,临时对象并非好东西,它是c++程序中很多BUG来源之一,c++编译器会在不影响程序最终执行效果的前提下,尽量减少临时对象的产生。

代码验证:

int main(void)
{
    //cls(5).show();    

    cls c1 = cls(6);

    return 0;
}

程序中,cls(6)很明显会产生一个临时对象,并将该临时对象赋值给c1类。这里的赋值操作自然会调用到拷贝构造函数,所以猜测程序的运行结果为:

cls(int i)          //cls(6)所致
cls(const cls& m)   //=所致
~cls()             //临时对象销毁所致
~cls()             //c1对象销毁所致

实际运行结果:
这里写图片描述

若依上面我猜测的程序执行流程运行程序,可见c1对象的产生需要经过两个构造函数:带参构造函数(临时对象调用)和拷贝构造函数(赋值类对象用),比起构造函数一次调用,显然效率低下得多,特别是在构造函数需要实现较多逻辑功能的时候。所以编译器做了优化,摈弃了临时对象的产生。优化后的代码应为:

源代码:cls c1 = cls(6);

编译器优化后:cls c1 = 6;

所以运行结果如上图所示。

回到一开始的问题,类中

cls()
{
    cls(0);
}

事实上,cls(0)会生成一个临时对象,而0是初始化这个临时对象的。该行代码执行过后,临时对象便被销毁,所以不能实现程序预先的目的。在实际中,若确实要实现代码复用的功能,可以写成:

class cls
{
public:
    int a;
    void init(int b)
    {
        a = b;
    }

    cls(int i)
    {
        init(i);
        std::cout << "cls(int i)" << std::endl;
    }

    cls()
    {
        init(a);
        std::cout << "cls()" << std::endl;
    }

    cls(const cls& m)   //拷贝构造函数
    {
        std::cout << "cls(const cls& m)" << std::endl;
    }

    void show()
    {
        std::cout << "a = " << a << std::endl;
    }

    ~cls()
    {
        std::cout << "~cls()" << std::endl;
    }
};

这样就可以避免临时对象的产生了。

你可能感兴趣的:(C/C++编程,c/c++语言,临时对象,编译器优化)