全栈开发知识库

3.引用参数和值参数

何时使用引用参数

使用引用参数的主要原因有两个:

  • 程序员能修改调用函数中的数据对象
  • 通过传递引用而不是整个数据对象,可以提高程序的运行速度。

当数据对象较大时(如结构和类对象),第二个原因最重要。
这些也是使用指针参数的原因。
这是有道理的,因为引用参数实际上是基于指针的代码的另一个接口。
那么,什么时候应该使用引用、什么时候应该使用指针呢? 什么时候应该按值传递呢?
下面是一些知道原则:

对于使用传递的值而不作修改的函数。

  • 如果数据对象很小,如内置数据类型或小型结构,则按值传递
  • 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针
  • 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间
  • 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是C++新增这项特性的主要原因。因此,传递类对象的标准方式是按引用传递。

对于修改调用函数中数据的函数:

  • 如果数据对象是内置数据类型,则使用指针。如果看到诸如fixit(&x)这样的代码,则很明显,该函数将修改x。
  • 如果数据对象是数组,则只能使用指针
  • 如果数据对象是结构,则使用指针或引用
  • 如果数据对象是类对象,则使用引用

指针引用

在C语言中,如果想改变指针本身而不是它所指向的内容,函数声明可能像这样:

void f(int **);

当传递它时,必须取得指针的地址:

int i = 47;
int *ip = &i;
f(&ip);

对于C++中的引用,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址,因此:

#include <iostream>
using namespace std;

void increment(int *&i) {
    i++;
}

int main() {
    int *i = 0;
    cout << "i = " << i << endl;
    increment(i);
    cout << "i = " << i << endl;
}

通过运行这个程序,将会看到指针本身增加了,而不是它指向的内容增加了。

运算符重载

=,[],()和->操作符只能通过成员函数进行重载。

<< 和 >> 只能通过全局函数配合友元函数进行重载。

不要重载&&和||操作符,因为无法实现短路规则

MyString.h

//
// Created by xuchuanren on 2023/11/15.
//

#ifndef CPPDEMO_MYSTRING_H
#define CPPDEMO_MYSTRING_H

#include <iostream>

using namespace std;

class MyString {
    // 声明友元
    friend istream &operator>>(istream &in, MyString &ob);

    friend ostream &operator<<(ostream &out, MyString &ob);

private:
    char *str;
    int size;

public:
    MyString();

    MyString(const char *str);

    MyString(const MyString &ob);

    ~MyString();

    int getSize() const;

    char &operator[](int pos);

    MyString &operator=(const MyString &str);

    MyString &operator=(const char *str);

    MyString &operator+(const MyString &ob);
};


#endif //CPPDEMO_MYSTRING_H

MyString.cpp

//
// Created by xuchuanren on 2023/11/15.
//

#include "MyString.h"
#include <iostream>

using namespace std;

MyString::MyString() {
    str = nullptr;
    size = 0;
    cout << "no paramter constructor" << endl;
}

MyString::MyString(const char *str) {
    this->str = new char[strlen(str) + 1];
    strcpy(this->str, str);
    size = strlen(str);
    cout << "parameter constructor" << endl;
}

MyString::MyString(const MyString &ob) {
    this->str = new char[strlen(ob.str) + 1];
    strcpy(str, ob.str);
    size = ob.size;
    cout << "copy constructor" << endl;
}

int MyString::getSize() const {
    return size;
}
// 因为<<中要用到类外的ostream,所以要用全局函数来实现重载运算符
// 但是在全局函数中又要用到MyString中的属性,所以要在头文件中声明为友元函数
ostream &operator<<(ostream &out, MyString &ob) {
    out << ob.str << endl;
    return out;
}

istream &operator>>(istream &in, MyString &ob) {
    if (ob.str != nullptr) {
        delete[] ob.str;
        ob.str = nullptr;
    }

    char buf[1024] = "";
    in >> buf;
    ob.str = new char[strlen(buf) + 1];
    strcpy(ob.str, buf);
    ob.size = strlen(buf);
    return in;
}

char &MyString::operator[](int index) {
    if (index >= 0 && index < size) {
        return str[index];
    } else {
        cout << "invalid index" << endl;
    }
}
// =号运算符的重载不会用到外部的类,用成员函数实现重载即可
MyString &MyString::operator=(const MyString &ob) {
    if (str != nullptr) {
        delete[] str;
        str = nullptr;
    }
    str = new char[ob.size + 1];
    strcpy(str, ob.str);
    size = ob.size;
    return *this;
}

MyString::~MyString() {
    if (str != nullptr) {
        delete[] str;
        str = nullptr;
    }
    cout << "deconstructor" << endl;
}

MyString &MyString::operator=(const char *str) {
    if (this->str != nullptr) {
        delete[] this->str;
        this->str = nullptr;
    }
    this->str = new char[strlen(str) + 1];
    strcpy(this->str, str);
    size = strlen(str);
    return *this;
}

MyString &MyString::operator+(const MyString &ob) {
    int newSize = this->size + ob.size;
    char *tempStr = new char[newSize + 1];
    memset(tempStr, 'c', newSize + 1);
    cout << "size : " << tempStr << endl;
    strcpy(tempStr, this->str);
    strcat(tempStr, ob.str);
    cout << "size : " << tempStr << endl;
    static MyString newString(tempStr);
    if (tempStr != nullptr) {
        delete[] tempStr;
        tempStr = nullptr;
    }
    return newString;
}


  • 邮箱 :charon.chui@gmail.com
  • Good Luck!
本页由 Markdown 自动渲染 · 共 628 篇笔记