为什么有时候C++运算符重载要返回引用,附对象生存周期
2017-08-31 15:36
302 查看
ヽ(・ω・。)ノ这个问题好几次想起来要记下来 结果都给忘了,写在这里以防哪天手误删了word里的笔记。
---------------------------------------------------------
原因如下:
(1)允许连续赋值,举个栗子:
(2)防止返回对象时调用拷贝构造函数、析构函数产生额外开销。
-------------------------------------------------------------------
(,,• ₃ •,,)嗨呀返回引用原来效率这么高!但是要当心不能不分场合的返回引用。
比如:不可以返回一个局部变量的引用,它的生存周期只在函数体内。
现在,如果要返回一个对象,值得注意的是我们最好返回一个临时对象。
由于C++编译器的优化功能会直接在主函数栈帧上拷贝构造新对象而减少产生一个临时对象的构造、析构开销。
临时对象和局部对象可不一样!临时对象就是没有名字的对象,它的生存周期只存在于当前语句。
当然有种情况例外,假设我们现在有一个类Test,
Test &p = Test(); //产生临时对象,使p成为它的别名,对象不会马上析构而是等离开p的作用域才析构。
---------------------------------------------------------------------------------------------------------------
既然提到临时对象局部对象就顺便记下对象生存周期:
//对象生存周期
class Test
{
public:
Test(int a=5, int b=5):ma(a), mb(b)//带默认值
private:
int ma;
int mb;
};
Test t1(10,10); //构造t1
//构造t5
int main()
{
Test t2(20,20); //构造t2
Test t3 = t2; //t2拷贝构造t3
static Test t4 = Test(30,30); //直接构造t4(这里有个编译器优化)
t2 = Test(40,40);
//构造临时对象给t2赋值,临时对象析构
t2 = (Test)(50,50);
//构造临时对象Test(50)给t2赋值,临时对象析构
t2 = 60;
//构造临时对象Test(60)给t2赋值,临时对象析构
Test *p1 = new Test(70,70);
//堆上 构造对象
Test *p2 = new Test[2];
//堆上 构造数组对象Test()
Test *p3 = &Test(80,80); //构造临时对象,临时对象析构
Test &q = Test(90,90);
//构造局部对象,使q成为它的别名
delete p1;
//p1析构
delete []p2;
//p2析构
}
//p4,t3,t2,t4,t5,t1析构
Test t5(100,100);
--------------------------------------------------------------------------------------------------------------
先写这么多=。=以免字太多自己都看不下去,
---------------------------------------------------------
原因如下:
(1)允许连续赋值,举个栗子:
class CMyString//咳,就拿上课讲过的代码好了 { public: CMyString(char *ptr=NULL) { if(ptr != NULL) { mpStr = new char[strlen(ptr)+1]; strcpy(mpStr, ptr); } else { mpStr = new char[1]; *mpStr = 0; } } CMyString(const CMyString &src) { mpStr = new char[strlen(src.mpStr)+1]; strcpy(mpStr, src.mpStr); } CMyString& operator=(const CMyString &src)
{ if(this == &src) return *this; delete []mpStr; mpStr = new char[strlen(src.mpStr)+1]; strcpy(mpStr, src.mpStr); return *this; }
//等号重载要记得(1)判断自赋值(2)释放原空间(3)重新申请空间并赋值。 ~CMyString() { delete []mpStr; mpStr = NULL; } bool operator>(const CMyString &src) { return strcmp(mpStr, src.mpStr) > 0; } bool operator<(const CMyString &src) { return strcmp(mpStr, src.mpStr) < 0; } bool operator==(const CMyString &src) { return strcmp(mpStr, src.mpStr) == 0; } char& operator[](int index){return mpStr[index];} //通过下标访问不仅要实现读的功能也要具有写的功能 private: char *mpStr; friend ostream& operator<<(ostream &out, const CMyString &src); friend CMyString operator+(const CMyString &lhs, const CMyString &rhs);
//嘛,参数加const不仅是为了防止“原版”被改变也是为了让它既能接收const形参也能接受非const参数
//那为什么加引用呢?这样可以防止传参时对参数进行拷贝以提高效率
};
CMyString operator+(const CMyString &lhs, const CMyString &rhs)
{
int size = lhs.size() + rhs.size() + 1;
char *p = new char[size];
strcpy(p, lhs.mpStr);
strcat(p, rhs.mpStr);
CMyString temp(p);
delete []p;
return temp;
}
ostream& operator<<(ostream &out, const CMyString &src)
{
out<<src.mpStr;return out;
}
int main()
{
CMyString str1 = "aaa";
CMyString str2 = "bbb";
CMyString str3 = str1 = str2;//通过重载实现连续赋值
cout<<"str1"<<str1<<endl;
cout<<"str2"<<str2<<endl; str3[2] = 'p';//通过下标实现赋值 cout<<str3[2]<<endl;//通过下表实现访问 cout<<"str3"<<str3<<endl; }
(2)防止返回对象时调用拷贝构造函数、析构函数产生额外开销。
-------------------------------------------------------------------
(,,• ₃ •,,)嗨呀返回引用原来效率这么高!但是要当心不能不分场合的返回引用。
比如:不可以返回一个局部变量的引用,它的生存周期只在函数体内。
现在,如果要返回一个对象,值得注意的是我们最好返回一个临时对象。
由于C++编译器的优化功能会直接在主函数栈帧上拷贝构造新对象而减少产生一个临时对象的构造、析构开销。
临时对象和局部对象可不一样!临时对象就是没有名字的对象,它的生存周期只存在于当前语句。
当然有种情况例外,假设我们现在有一个类Test,
Test &p = Test(); //产生临时对象,使p成为它的别名,对象不会马上析构而是等离开p的作用域才析构。
---------------------------------------------------------------------------------------------------------------
既然提到临时对象局部对象就顺便记下对象生存周期:
//对象生存周期
class Test
{
public:
Test(int a=5, int b=5):ma(a), mb(b)//带默认值
private:
int ma;
int mb;
};
Test t1(10,10); //构造t1
//构造t5
int main()
{
Test t2(20,20); //构造t2
Test t3 = t2; //t2拷贝构造t3
static Test t4 = Test(30,30); //直接构造t4(这里有个编译器优化)
t2 = Test(40,40);
//构造临时对象给t2赋值,临时对象析构
t2 = (Test)(50,50);
//构造临时对象Test(50)给t2赋值,临时对象析构
t2 = 60;
//构造临时对象Test(60)给t2赋值,临时对象析构
Test *p1 = new Test(70,70);
//堆上 构造对象
Test *p2 = new Test[2];
//堆上 构造数组对象Test()
Test *p3 = &Test(80,80); //构造临时对象,临时对象析构
Test &q = Test(90,90);
//构造局部对象,使q成为它的别名
delete p1;
//p1析构
delete []p2;
//p2析构
}
//p4,t3,t2,t4,t5,t1析构
Test t5(100,100);
--------------------------------------------------------------------------------------------------------------
先写这么多=。=以免字太多自己都看不下去,
相关文章推荐
- 为什么CreateThread()调用创建线程时,系统设置线程内核对象的引用计数为1,在Create函数返回前是2
- 为什么C++中千万不要返回局部对象或变量的引用和指针
- 引用计数自动管理对象的生存周期
- 为什么重载输出流符号的时候一定要返回引用
- 引用计数自动管理对象的生存周期
- 为什么retainCount返回的对象引用值总是跟预期的不一样呢?
- c++为什么重载输出流符号的时候一定要返回引用
- Effective C++ 第二版 22)传引用 23)返回对象 24)函数重载vs缺省值
- 重载=时返回对象引用与非引用的区别
- 为什么不能从子函数中返回临时对象的指针和引用,却可以返回一个临时变量的值
- 为什么C++中千万不要返回局部对象或变量的引用和指针
- c++中重载输出操作符,为什么要返回引用
- c++ 重载 = 为什么返回引用类型
- android中引用方法的时候,有时候要new一个对象才能引用,有时候直接.方法就可以了,为什么
- Effective C++(10) 重载赋值操作符时,返回该对象的引用(retrun *this)
- 了解临时对象的来源 (深刻理解为什么不能返回一个临时变量的引用)
- Effective C++(10) 重载赋值操作符时,返回该对象的引用(retrun *this)
- effective c++ 条款23总结: 必须返回一个对象时不要试图返回一个引用
- 为什么static成员的类型可以是类本身?又为什么非static成员被限定声明为其自身类对象的指针或引用?
- C++——面向对象(三)——各种对象的生存周期