【C++】返回值是类名和返回值是引用的区别

返回非引用类型:

函数的返回值用于初始化在调用函数时创建的临时对象(temporary object),如果返回类型不是引用,在调用函数的地方会将函数返回值复制给临时对象。
在求解表达式的时候,如果需要一个地方存储其运算结果,编译器会创建一个没命名的对象,这就是临时对象。C++程序员通常用temporary这个术语来代替temporary object。
用函数返回值初始化临时对象与用实参初始化形参的方法是一样的。
当函数返回非引用类型时,其返回值既可以是局部对象,也可以是求解表达式的结果。

返回引用类型:

当函数返回引用类型时,没有复制返回值,相反,返回的是对象本身。
千万不要返回局部对象的引用!千万不要返回指向局部对象的指针!
当函数执行完毕时,将释放分配给局部对象的存储空间。此时对局部对象的引用就会指向不确定的内存!返回指向局部对象的指针也是一样的,当函数结束时,局部对象被释放,返回的指针就变成了不再存在的对象的悬垂指针。

返回引用时,要求在函数的参数中,包含有以引用方式或指针方式存在的,需要被返回的参数。

如果返回对象,最后多执行一次拷贝构造函数,如果返回引用,直接返回现存对象

#include <iostream>
using namespace std;

class Timer
{
public:
    Timer();
    Timer(int, int, int);
    friend Timer  &operator+(Timer&, Timer&);
    friend Timer operator-(Timer&, Timer&);
    friend ostream& operator<<(ostream &out, Timer &t);
    friend istream& operator>>(istream &in, Timer &t);
private:
    int hour, minute, second;
};

Timer::Timer()
{
    hour = 0;
    minute = 0;
    second = 0;
}

Timer::Timer(int hour, int minute, int second)
{
    this->hour = hour;
    this->minute = minute;
    this->second = second;
}

Timer & operator+(Timer& a, Timer &b)
{
    a.second = a.second + b.second;
    a.minute = a.minute + b.minute;
    a.hour = a.hour + b.hour;
    if (a.second >= 60)
    {
        a.second = a.second - 60;
        a.minute++;
    }
    if (a.minute >= 60)
    {
        a.minute = a.minute - 60;
        a.hour++;
    }
    return a;
}

Timer operator-(Timer &a, Timer &b)
{
    Timer c;
    c.hour = a.hour - b.hour;
    c.minute = a.minute - b.minute;
    c.second = a.second - b.second;
    if (c.second < 0)
    {
        c.second += 60;
        c.minute--;
    }
    if (c.minute < 0)
    {
        c.minute += 60;
        c.hour--;
    }
    return c;
}

ostream& operator<<(ostream &out, Timer &t)
{
    out << t.hour << ":" << t.minute << ":" << t.second << endl;
    return out;
}

istream& operator>>(istream&in, Timer &t)
{
    cout << "Input hours and minutes." << endl;
    in >> t.hour >> t.minute >> t.second;
    return in;
}

int main()
{
    Timer t1, t2, t3, t4;
    cin >> t1 >> t2;
    cout << "t1=" << t1;
    cout << "t2=" << t2;
    t3 = t1 + t2;
    cout << "t3=t1+t2=" << t3;
    t4 = t1 - t2;
    cout << "t4=t1-t2=" << t4;
    return 0;
}

刚开始我将函数声明为:

friend Timer&operator+(Timer&,Timer&);
friend Timer&operator-(Timer&,Timer&);

对于<<,>>的重载声明的和长代码一样。但是这样做之后我发现出现异常。
在Time &operator+(Timer&t1,Timer&t2)里我声明了一个Timer的局部变量,而当函数调用结束后,该指针变成了悬挂指针。
所以,一定谨记不要在返回值为引用的函数中返回局部变量。

<think>我们正在讨论C++中析构函数的语法,特别是波浪线(~)的含义。根据引用[2]中的描述,析构函数的写法是:~类名。它没有参数,且一个有且只有一个析构函数。 引用[1][3]都提到了虚析构函数的概念,这在多态中非常重要,可以确保当通过基指针删除派生对象时,能够正确调用派生的析构函数。 因此,波浪线(~)是析构函数的标识符,它位于类名前,表示这是一个析构函数。析构函数在对象生命周期结束时自动调用,用于释放资源。 下面我将详细解释析构函数的语法含义:</think>### C++析构函数语法详解:`~`符号的含义与用法 #### 1. `~`符号的核心含义 在C++中,**波浪号`~`是析构函数的标识符**,它有两个关键作用: - **语法标记**:出现在类名前,明确声明这是一个析构函数 - **语义表示**:表示该函数执行对象生命周期结束时的"反向构造"操作 #### 2. 基本语法结构 ```cpp class ClassName { public: ~ClassName(); // 声明析构函数 }; // 定义析构函数 ClassName::~ClassName() { // 资源清理代码 } ``` - **必须与同名**:`~`后必须紧跟所属的名称 - **无返回值**:不指定返回类型(包括void) - **无参数**:不能带任何参数(包括void参数) - **唯一性**:每个只能有一个析构函数[^2] #### 3. 关键特性解析 | 特性 | 说明 | 示例 | |------|------|------| | **自动调用** | 对象离开作用域时自动触发 | 局部变量在代码块结束时析构 | | **资源释放** | 释放对象占用的非托管资源 | 关闭文件句柄、释放内存等 | | **继承链调用** | 派生析构后自动调用基析构 | 派生→基析构顺序[^3] | | **虚析构函数** | 多态场景下必须声明为virtual | `virtual ~Base(){}`[^1] | #### 4. 使用场景示例 **场景1:基础资源释放** ```cpp class FileHandler { public: FileHandler(const char* filename) { file = fopen(filename, "r"); } ~FileHandler() { if(file) fclose(file); // 确保文件关闭 cout << "File closed\n"; } private: FILE* file; }; // 使用示例 void processFile() { FileHandler f("data.txt"); // 构造函数打开文件 // ...操作文件... } // 离开作用域时自动调用析构关闭文件 ``` **场景2:多态对象销毁(虚析构关键作用)** ```cpp class Base { public: virtual ~Base() { cout << "Base destroyed\n"; } // 虚析构 }; class Derived : public Base { public: ~Derived() { cout << "Derived destroyed\n"; } // 自动成为虚函数 }; int main() { Base* obj = new Derived(); delete obj; // 正确调用顺序: Derived::~ → Base::~ } ``` 输出: ``` Derived destroyed Base destroyed ``` 若省略`virtual`,将只调用`Base::~Base()`导致资源泄漏[^1] #### 5. 与构造函数的对比 | 特性 | 构造函数 | 析构函数 | |--------------|--------------------------|---------------------------| | **符号** | 类名 | ~类名 | | **调用时机** | 对象创建时 | 对象销毁时 | | **数量** | 可多个(重载) | 唯一 | | **参数** | 可有参数 | 无参数 | | **继承顺序** | 基→成员→派生[^3] | 派生→成员→基[^3] | #### 6. 何时需要显式定义析构函数? 当涉及以下操作时**必须自定义析构函数**: - 直接管理原始内存资源(new/delete) - 持有文件/网络句柄等系统资源 - 包含需要特殊清理的成员对象 - 作为多态基(需声明virtual析构)[^1] > ⚠️ 默认析构函数仅释放成员占用的内存,不会处理指针指向的堆内存或外部资源[^2]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值