C++学习 十四、类的进阶(6)返回对象
前言
本篇首先小结类中动态内存的使用,然后记录返回对象。
类与动态内存小结
- 构造函数中使用
new
分配动态内存,则析构函数中必须使用delete
释放动态内存。 - 析构函数只有一个。因此有多个构造函数时,要考虑
new
与new []
的兼容性。 - 构造函数如果分配动态内存,则需要定义一个深拷贝复制构造函数,重载一个深拷贝赋值运算符。
函数返回对象
函数除了返回普通对象以外,还可以返回对象的引用(或指针),const对象,const引用对象或指针。
返回非const对象
上篇提到,函数返回对象会调用复制构造函数(编译器关闭RVO),增加了程序运行时间和内存使用。
- 当需要返回的对象是局部变量,则返回普通对象。
返回const对象
返回const类型的目的在于,const常量不会被修改。
- 当需要返回的对象时局部变量,并且不希望函数调用语句被赋值,则返回const对象。
返回非const引用对象
返回对象的引用(指针)的好处是,不会调用复制构造函数。
- 当需要返回的对象是函数传入的引用,并且返回的对象后续可被修改,则返回非const对象的引用
注意:返回的引用必须是在函数结束后仍然存在的对象。在函数中创建的局部对象不能通过引用和指针返回。
返回const引用对象
返回const引用,一方面可以防止函数调用语句被赋值,另一方面如果要返回传入的const引用,则返回类型必须是const引用。
示例
#include <cstdio>
#include <iostream>
#include <cstring>
using std::ostream;
class A{
private:
int a_;
int b_;
int c_;
public:
A();
A(int, int, int);
A operator- (const A&) const;
const A operator+ (const A&) const;
const A& operator= (const A&);
friend ostream& operator<< (ostream& os,
const A&);
};
A::A(): a_(0), b_(0), c_(0) {}
A::A(int a, int b, int c): a_(a), b_(b), c_(c) {}
A A::operator- (const A& s) const{
int a = a_ - s.a_;
int b = b_ - s.b_;
int c = c_ - s.c_;
return A(a, b, c);
}
const A A::operator+ (const A& s) const{
int a = a_ + s.a_;
int b = b_ + s.b_;
int c = c_ + s.c_;
return A(a, b, c);
}
ostream& operator<< (ostream& os, const A& s){
os << s.a_ << " " <<
s.b_ << " " <<
s.c_ << '\n';
return os;
}
const A& A::operator= (const A& s){
return s;
}
const A func(const A& s){
return s;
}
const A& funcc(const A& s){
return s;
}
int main(){
A s1(1, 1, 1);
A s2(2, 2, 2);
// insert code
return 1;
}
在上面的代码中,如果在// insert code
后插入下面的代码:
s1 - s2 = s1; // ok
s1 + s2 = s2; // error!
s1 + s2 = s2;
报error: passing 'const A' as 'this' argument discards qualifiers [-fpermissive];
,原因在于返回const对象能够防止调用后被赋值。
s1 = s1 = s1; // ok
(s1 = s1) = s1; // error!
=
是右结合性,因此s1 = s1 = s1
实际上是s1 = (s1 = s1)
没问题,而(s1 = s1) = s1
返回const引用,自然也会报error: passing 'const A' as 'this' argument discards qualifiers [-fpermissive]
A func(const A& s){ // ok
return s;
}
A& funcc(const A& s){ // error!
return s;
}
const A& funccc(A& s){ // ok
return s;
}
如果把函数func
与funcc
的返回类型改为非const,func
没问题但funcc
报error: binding reference of type 'A&' to 'const A' discards qualifiers
,
func
返回对象(变量),复制构造函数根据s
创建一个与返回类型相同的临时对象,因此返回是否是const无所谓。
funcc
返回引用,因此不会创建临时变量,return s;
返回s
,s
是const引用,如果返回类型是非const,则s
的const状态并不安全,这违反C++的逻辑。
funccc
中return s;
中的s
是非const引用,返回类型是const,此时返回的s
从非const变为const,状态安全,不违反C++逻辑。
总而言之,const
关键字常出现的报错discards qualifiers
,核心原因就在于维护变量状态的安全性。如果编译器认为返回方式不安全,就会报discards qualifiers
。
后记
下篇进入到类的继承章节。