标签:匿名 div class 拷贝构造 png 函数的参数 运算 img splay
一个类包含:构造、析构、拷贝构造、赋值构造、常对象取地址、普通对象取地址基本函数
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; }
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); }
运行结果:
在上面的代码中,返回tmp时候,必须先创建一个临时对象,然后用tmp去拷贝构造临时对象,因为tmp在函数结束时候,就会析构,必须现将其拷贝到一个临时对象中保存,就会调用拷贝构造函数,临时对象和普通对象在同一种空间中,所以它比函数中局部对象更迟析构,函数内的对象,函数运行完,就直接析构了。
现在修改一下:
int main() { Test t(100); Test t2=fun(t); }
运行结果:
并没有把上面说到的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); }
运行结果:
可以看到,因为参数引用传递,所以少了一次拷贝构造。
现在修改一下:
Test& fun(Test &x) { int value = x.GetData(); Test tmp(value); return tmp; } int main() { Test t(100); Test t2=fun(t); }
因为现在返回值是引用&,打印出t2的值是个随机值,说明函数作用域内的对象,在运行完就直接析构了,这时候,用这块已经被析构的内存构造的对象当然是个随机值了。
运行结果
现在修改一下:
Test fun(Test &x) { int value = x.GetData(); return Test(value); } int main() { Test t(100); Test t2=fun(t); }
运行结果:
经过编译器的优化,编译器直接构造了t2,不会从临时对象向t2的拷贝构造。
现在修改一下:
Test fun(Test &x) { int value = x.GetData(); return Test(value); } int main() { Test t(100); Test t2; t2 = fun(t); }
运行结果:
这时候就会用返回的匿名对象再构造一个临时对象,然后用临时对象来赋值构造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))
执行结果是:
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; }
标签:匿名 div class 拷贝构造 png 函数的参数 运算 img splay
原文地址:https://www.cnblogs.com/WindSun/p/11324473.html