C++学习 十四、类的进阶(6)返回对象

C++学习 十四、类的进阶(6)返回对象

前言

本篇首先小结类中动态内存的使用,然后记录返回对象。

类与动态内存小结

  • 构造函数中使用new分配动态内存,则析构函数中必须使用delete释放动态内存。
  • 析构函数只有一个。因此有多个构造函数时,要考虑newnew []的兼容性。
  • 构造函数如果分配动态内存,则需要定义一个深拷贝复制构造函数,重载一个深拷贝赋值运算符。

函数返回对象

函数除了返回普通对象以外,还可以返回对象的引用(或指针),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;
}

如果把函数funcfuncc的返回类型改为非const,func没问题但funccerror: binding reference of type 'A&' to 'const A' discards qualifiers

func返回对象(变量),复制构造函数根据s创建一个与返回类型相同的临时对象,因此返回是否是const无所谓。

funcc返回引用,因此不会创建临时变量,return s;返回ss是const引用,如果返回类型是非const,则s的const状态并不安全,这违反C++的逻辑。

funcccreturn s;中的s是非const引用,返回类型是const,此时返回的s从非const变为const,状态安全,不违反C++逻辑。

总而言之,const关键字常出现的报错discards qualifiers,核心原因就在于维护变量状态的安全性。如果编译器认为返回方式不安全,就会报discards qualifiers

后记

下篇进入到类的继承章节。

上一篇:puppeteer


下一篇:【C++】C++入门特性全解析