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!