zoukankan      html  css  js  c++  java
  • C++类的函数成员

    类的基本成员函数

    一个类包含:构造、析构、拷贝构造、赋值构造、常对象取地址、普通对象取地址基本函数

    class Test
    {
    public:
        Test(int data = 0) :m_data(data)
        {
            cout << "构造函数:" << this << endl;
        }
    
        ~Test()
        {
            cout << "析构:" << this << endl;
        }
    
        Test(const Test &t)
        {
            m_data = t.m_data;
            cout << "拷贝构造:" << this << endl;
        }
    
        Test operator=(const Test &t)
        {
            if (this != &t)
            {
                m_data = t.m_data;
            }
            cout << "赋值构造:" << this << endl;        //拷贝赋值
            return *this;
        }
    
        Test* operator&()
        {
            cout << "普通象取地址:" << this << endl;
            return this;
        }
    
        const Test* operator&()const
        {
            cout << "常对象取地址:" << this << endl;
            return this;
        }
    
        int GetData() const
        {
            return m_data;
        }
    private:
        int m_data;
    };
    
    int main()
    {
        Test t1(100);
        Test* t2 = &t1;
        const Test t3(300);
        const Test* t4 = &t3;
    }

    类中的const方法与普通方法

    class Test
    {
    public:
        Test(int data=0):m_data(data) {}
        //相当于void fun(Test* this) const
        void fun() const
        {
            cout << m_data <<endl;
        }
        //void fun(const Test *const this)
        void fun()
        {
            cout << m_data << endl;
        }
    
    private:
        int m_data;
    };

    void fun() const和void fun()是可以共存的

    如果不加const

    void fun()    // <==>void fun(Test* const this)

    加了const

    void fun() const  // <==> void fun(const Test *const this)

    1.因为函数后加了const就封锁了*this 为常量,就不能通过常量更改成员了

    2.两个函数的参数的类型不同,所以就可以重载

    3.经过调试也可以看出:如果同时有普通方法和常方法,普通对象调用的是普通方法,常量对象调用的是常方法。

    4.但是如果没有普通方法,只有常方法,普通对象也可以调用常方法,因为它没有其他选择。反之,如果没有常方法,只有普通方法,常量对象是无法调用普通方法的。因为:普通对象调用常方法,但只是不能修改而已,而常对象要调用普通方法,普通方法是不可以修改的,所以就不成立

    总结如下:

    1.const对象可以调用非const成员函数吗? //不可以

    2.非const对象可以调用const成员函数吗?//可以

    3.const成员函数内可以调用其他的非const成员函数吗?//不可以

    4.非const成员函数内可以调用其他的const成员函数吗?//可以

    ps:即权限缩小的话,都可以

    拷贝构造函数

    对象初始化对象会调用拷贝构造函数

    Test(const Test &t)
    {
        m_data = t.m_data;
        cout << "Copy Create Test Object!" << endl;
    }

    1.拷贝构造函数Test(const Test &t)的const可以去掉,但前提是用普通对象构造普通对象。如果是常对象就不能构造普通对象,一般为了保护参数,避免函数中修改参数,都会加上const。而且编译器默认就是带有const的拷贝构造函数

    2.拷贝构造函数的参数必须要加引用&,如果不加就会无限的调用拷贝构造函数,编译器也不允许。

    3.如果成员中没有指针,只是基本的类型,可以用默认的拷贝构造函数

    例子

    先看一个例子,看看什么时候会调用拷贝构造函数

    class Test
    {
    public:
        Test(int data=0):m_data(data) 
        {
            cout << "构造函数:"<<this<< endl;
        }
    
        Test(const Test &t)
        {
            m_data = t.m_data;
            cout << "拷贝构造:" <<this<< endl;
        }
    
        Test& operator=(Test &t)
        {
            if (this != &t)
            {
                m_data = t.m_data;
            }
            cout << "拷贝赋值:" <<this<< endl;
            return *this;
        }
        ~Test()
        {
            cout << "析构" <<this<< endl;
        }
    
        int GetData() const
        {
            return m_data;
        }
    private:
        int m_data;
    };
    
    Test fun(Test x)    //传递参数调用拷贝构造
    {
        int value = x.GetData();
        Test tmp(value);    //调用构造函数
        return tmp;    //返回tmp时候,必须先创建一个临时对象,然后用tmp去拷贝构造临时对象
    }
    
    int main()
    {
        Test t(100);    //调用构造函数
        fun(t);    
    }

    运行结果:

    d1c5e800-8dee-44af-b28d-44abf34a01c0[4]

    在上面的代码中,返回tmp时候,必须先创建一个临时对象,然后用tmp去拷贝构造临时对象,因为tmp在函数结束时候,就会析构,必须现将其拷贝到一个临时对象中保存,就会调用拷贝构造函数,临时对象和普通对象在同一种空间中,所以它比函数中局部对象更迟析构,函数内的对象,函数运行完,就直接析构了。

    现在修改一下:

    int main()
    {
        Test t(100);
        Test t2=fun(t);
    }

    运行结果:

    cc30b373-8289-4c20-b5b8-3d81ab0e966f

    并没有把上面说到的tmp对象赋值给t2,这时候编译器做了优化,因为有对象需要返回的那个tmp来构造,所以就不需要去构造临时对象,而是直接用tmp构造了t2。

    现在修改一下:

    Test fun(Test &x)
    {
        int value = x.GetData();
        Test tmp(value);
        return tmp;
    }
    
    int main()
    {
        Test t(100);
        Test t2=fun(t);
    }

    运行结果:

    d32bd403-a8cf-49d4-ae93-053b4240d3cf

    可以看到,因为参数引用传递,所以少了一次拷贝构造。

    现在修改一下:

    Test& fun(Test &x)
    {
        int value = x.GetData();
        Test tmp(value);
        return tmp;
    }
    
    int main()
    {
        Test t(100);
        Test t2=fun(t);
    }

    因为现在返回值是引用&,打印出t2的值是个随机值,说明函数作用域内的对象,在运行完就直接析构了,这时候,用这块已经被析构的内存构造的对象当然是个随机值了。

    运行结果

    36c6ce1d-f864-48bf-829e-bd8b3ac8d384[4]

    现在修改一下:

    Test fun(Test &x)
    {
        int value = x.GetData();
        return Test(value);
    }
    
    int main()
    {
        Test t(100);
        Test t2=fun(t);
    }

    运行结果:

    cbda9d16-b30e-4533-af11-ac9d74e22e28[4]

    经过编译器的优化,编译器直接构造了t2,不会从临时对象向t2的拷贝构造。

    现在修改一下:

    Test fun(Test &x)
    {
        int value = x.GetData();
        return Test(value);
    }
    
    int main()
    {
        Test t(100);
        Test t2;
        t2 = fun(t);
    }

    运行结果:

    dc63ab3a-b5e7-484f-82a7-957f269e957a[4]

    这时候就会用返回的匿名对象再构造一个临时对象,然后用临时对象来赋值构造t2。

    赋值构造函数

    Test& operator=(const Test &t)
    {
        if (this != &t)
        {
            m_data = t.m_data;
        }
        return *this;
    }

    1.const可以去掉,但必须是普通对象赋值构造普通对象,常对象就无法赋值构造普通对象了。一般为了保护参数,避免函数中修改参数对象,都会加上const。而且编译器默认就是带有const的赋值构造函数。

    2.参数的引用&可以去掉,那么就会多调用一次拷贝构造函数,效率降低。

    3.返回值不是必须的,可以为void,用引用返回值的原因是可以实现链式表达式,提高效率,将返回结果作为另外一个操作符的运算

    如:

    class{
        //...
        Test& operator=(const Test& t)
        {
            if (this != &t)
            {
                m_data = t.m_data;
            }
            cout << "赋值构造:" << this << endl;
            return *this;
        }
        ///...
    }
    
    int main()
    {
        Test t1(100);
        Test t2,t3;
        t3=t2 = t1;
        cout << t2.GetData() << " " << t3.GetData() << endl;
    }    //相当于:t3.operator=(t2.operator=(t1))

    执行结果是:

    66d49579-ca5b-4887-92be-f8f16d3544e0

    4.返回的类型也可以去掉引用&,但是返回就会调用拷贝构造函数

    class
    {
        //...
        Test operator=(const Test& t)
        {
            if (this != &t)
            {
                m_data = t.m_data;
            }
            cout << "赋值构造:" << this << endl;
            return *this;
        }
        //...
    }
    
    int main()
    {
        Test t1(100);
        Test t2;
        t2 = t1;
    }

    8c86b9bd-c569-45da-b8bf-ab829a58aea0

  • 相关阅读:
    正则
    cookie、sesion
    POJ-1509
    HDU-3374
    ZOJ-3822
    HDU-5492
    在什么情况下Java比C++快?
    HDU-5451
    SPOJ-913
    莫比乌斯反演入门
  • 原文地址:https://www.cnblogs.com/WindSun/p/11324473.html
Copyright © 2011-2022 走看看