目录
问题1:如何区分对象创建时,调用的是构造函数还是赋值重载函数?
如需咨询请添加个人微信:a15135158368
欢迎叨扰,多多交流
一、函数重载
函数重载(Function Overloading)允许在同一个作用域内定义多个同名函数,但这些函数必须有不同的参数列表(即参数的类型、个数或顺序不同)。
通过函数重载,C++程序可以根据传入参数的不同选择相应的函数来执行。
1. 参数类型不同的重载
#include <iostream>
// 重载函数,根据不同类型的参数执行不同的操作
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int main() {
int int_result = add(3, 4); // 调用的是int版本的add
double double_result = add(3.5, 2.5); // 调用的是double版本的add
std::cout << "int add result: " << int_result << std::endl;
std::cout << "double add result: " << double_result << std::endl;
return 0;
}
讲解
-
上面的代码中,函数
add
被重载了两次,一次用于处理int
类型参数,另一次用于处理double
类型参数。 -
当调用
add(3, 4)
时,编译器根据传递的参数类型选择int
版本的add
,而当调用add(3.5, 2.5)
时,编译器则选择double
版本的add
。
2. 参数个数不同的重载
#include <iostream>
// 重载函数,根据参数个数不同执行不同操作
int multiply(int a, int b) {
return a * b;
}
int multiply(int a, int b, int c) {
return a * b * c;
}
int main() {
int result1 = multiply(2, 3); // 调用的是两个参数版本的multiply
int result2 = multiply(2, 3, 4); // 调用的是三个参数版本的multiply
std::cout << "multiply(2, 3): " << result1 << std::endl;
std::cout << "multiply(2, 3, 4): " << result2 << std::endl;
return 0;
}
讲解
-
在这个例子中,
multiply
函数被重载了两次,一次是两个参数版本,一次是三个参数版本。 -
当调用
multiply(2, 3)
时,编译器选择两个参数版本的multiply
,而调用multiply(2, 3, 4)
时,编译器选择三个参数版本的multiply
。
3. 参数顺序不同的重载
#include <iostream>
// 重载函数,根据参数顺序不同执行不同操作
void display(int a, double b) {
std::cout << "int and double: " << a << " " << b << std::endl;
}
void display(double b, int a) {
std::cout << "double and int: " << b << " " << a << std::endl;
}
int main() {
display(3, 4.5); // 调用的是int, double版本的display
display(4.5, 3); // 调用的是double, int版本的display
return 0;
}
讲解
-
在这个例子中,函数
display
被重载了两次,两次的参数类型相同,但顺序不同。 -
当调用
display(3, 4.5)
时,编译器选择int, double
顺序版本,而调用display(4.5, 3)
时,编译器选择double, int
顺序版本。
4. 默认参数与函数重载
#include <iostream>
// 重载函数以及带有默认参数的函数
void printMessage(std::string message, int times = 1) {
for (int i = 0; i < times; ++i) {
std::cout << message << std::endl;
}
}
void printMessage(std::string message, double times) {
std::cout << "Message: " << message << ", repeated " << times << " times." << std::endl;
}
int main() {
printMessage("Hello"); // 调用的是带默认参数的int版本的printMessage
printMessage("Hello", 3); // 调用的是int版本的printMessage
printMessage("Hello", 2.5); // 调用的是double版本的printMessage
return 0;
}
讲解
-
在这个例子中,
printMessage
函数被重载了两次,一次接受int
型times
参数,并且times
有默认值,另一次接受double
型times
参数。 -
当调用
printMessage("Hello")
时,编译器选择第一个版本,且使用默认参数times = 1
。 -
当调用
printMessage("Hello", 3)
时,编译器选择第一个版本,因为传递的3
是int
类型。 -
当调用
printMessage("Hello", 2.5)
时,编译器选择第二个版本,因为传递的2.5
是double
类型。
二、运算符重载
在C++中,运算符重载允许程序员为用户自定义的类型(如类或结构体)定义新的运算符行为。这意味着可以对类对象使用像 +
、-
、*
等运算符,类似于对内置类型(如 int
、float
等)进行操作。
简单的来说,就是将变量使用的运算符重载为了对象使用。
1. 运算符重载的基本语法
运算符重载通过在类中定义一个特殊的成员函数或友元函数来实现。
重载函数的函数名为 operator
后跟要重载的运算符。例如:
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
// 构造函数
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// 重载加法运算符
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 显示复数
void display() const {
std::cout << "(" << real << " + " << imag << "i)" << std::endl;
}
};
int main() {
Complex c1(3.0, 4.0); // 创建复数 c1 = 3 + 4i
Complex c2(1.0, 2.0); // 创建复数 c2 = 1 + 2i
// 使用重载的加法运算符
Complex c3 = c1 + c2;
// 显示结果
std::cout << "c1 = "; c1.display();
std::cout << "c2 = "; c2.display();
std::cout << "c1 + c2 = "; c3.display();
return 0;
}
c1 = (3 + 4i)
c2 = (1 + 2i)
c1 + c2 = (4 + 6i)
示例讲解
-
重载加法运算符的定义:
Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); }
-
operator+
是我们定义的一个函数,用于重载+
运算符。 -
const Complex& other
是该函数的参数,表示加号右边的复数对象。使用const
表明我们不会修改传入的对象,使用引用是为了避免不必要的拷贝操作。 -
const
放在函数末尾,表明这个函数不会修改调用该函数的对象内部的成员变量。 -
函数的返回类型是
Complex
,即返回一个新的复数对象。
-
-
函数内部的操作:
return Complex(real + other.real, imag + other.imag);
-
real + other.real
表示将当前对象的实部与other
的实部相加。 -
imag + other.imag
表示将当前对象的虚部与other
的虚部相加。 -
最后返回一个新的
Complex
对象,它的实部和虚部分别是上述两个相加的结果。
-
-
运算符的使用:
Complex c3 = c1 + c2;
-
当我们编写
c1 + c2
时,编译器会调用operator+
函数。 -
c1
是调用对象,因此real
和imag
是c1
的成员。 -
c2
是传入的参数对象(即other
),其实部和虚部用于与c1
的对应部分相加。 -
返回的新对象
c3
包含了相加后的实部和虚部。
-
通过这个重载,我们可以像处理内置类型一样,直接对 Complex
对象使用 +
运算符,从而使代码更具可读性和直观性。
2. 运算符重载的常见用法
2.1 重载 <<
和 >>
运算符(用于输入输出)
#include <iostream>
class Complex {
private:
double real;
double imag;
public:
// 构造函数
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}
// 重载加法运算符
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 重载输出运算符 <<
friend std::ostream& operator<<(std::ostream& os, const Complex& c) {
os << "(" << c.real << " + " << c.imag << "i)";
return os;
}
// 重载输入运算符 >>
friend std::istream& operator>>(std::istream& is, Complex& c) {
is >> c.real >> c.imag;
return is;
}
};
int main() {
Complex c1, c2;
// 从输入流读取复数
std::cout << "输入第一个复数(实部和虚部): ";
std::cin >> c1;
std::cout << "输入第二个复数(实部和虚部): ";
std::cin >> c2;
// 使用重载的加法运算符
Complex c3 = c1 + c2;
// 使用重载的输出运算符显示结果
std::cout << "c1 = " << c1 << std::endl;
std::cout << "c2 = " << c2 << std::endl;
std::cout << "c1 + c2 = " << c3 << std::endl;
return 0;
}
输入第一个复数(实部和虚部): 3 4
输入第二个复数(实部和虚部): 1 2
c1 = (3 + 4i)
c2 = (1 + 2i)
c1 + c2 = (4 + 6i)
示例讲解
-
重载
<<
运算符:// 重载输出运算符 << friend std::ostream& operator<<(std::ostream& os, const Complex& c) { os << "(" << c.real << " + " << c.imag << "i)"; return os; } //std::cout << "输入第一个复数(实部和虚部): ";
-
operator<<
是一个友元函数,它重载了<<
运算符,使我们可以将Complex
对象直接输出到输出流(如std::cout
)。 -
std::ostream& os
是输出流对象的引用,用于表示输出的目标(例如,控制台)。 -
const Complex& c
是要输出的复数对象。 -
在函数内部,使用
os <<
将复数的格式化字符串输出到流中。最后返回os
以支持链式操作。
-
-
重载
>>
运算符:// 重载输入运算符 >> friend std::istream& operator>>(std::istream& is, Complex& c) { is >> c.real >> c.imag; return is; } //std::cin >> c2;
-
operator>>
是另一个友元函数,重载了>>
运算符,使我们可以从输入流(如std::cin
)读取Complex
对象。 -
std::istream& is
是输入流对象的引用,用于表示输入的来源(例如,键盘)。 -
Complex& c
是要输入的复数对象的引用。 -
在函数内部,使用
is >>
依次读取实部和虚部,并将它们存储到c
的成员变量中。最后返回is
以支持链式操作。
-
-
在
main
函数中的使用:-
首先,提示用户输入两个复数的实部和虚部,使用
>>
运算符读取这些值。 -
然后,使用重载的
+
运算符将两个复数相加。 -
最后,使用
<<
运算符将结果输出到控制台。
-
通过重载 <<
和 >>
运算符,我们可以直接使用标准的输入输出方式来处理 Complex
对象,使得代码更为简洁易读。
2.2 重载 ++
和 --
运算符(用于自增自减)
#include <iostream>
class Counter {
private:
int count;
public:
// 构造函数
Counter(int c = 0) : count(c) {}
// 前置++运算符
Counter& operator++() {
++count; // 先自增,再返回自身的引用
return *this;
}
// 后置++运算符
Counter operator++(int) {
Counter temp = *this; // 保存当前状态
++count; // 自增
return temp; // 返回保存的未自增前的状态
}
// 显示当前计数值
void display() const {
std::cout << "Count: " << count << std::endl;
}
};
int main() {
Counter c1(5); // 创建一个初始值为5的Counter对象
// 使用前置自增运算符
std::cout << "使用前缀 ++:" << std::endl;
++c1;
c1.display(); // 显示 c1 的当前值
// 使用后置自增运算符
std::cout << "使用后缀 ++:" << std::endl;
c1++;
c1.display(); // 显示 c1 的当前值
return 0;
}
使用前缀 ++:
Count: 6
使用后缀 ++:
Count: 7
示例讲解
-
构造函数:
Counter(int c = 0) : count(c) {}
-
这是一个构造函数,用于初始化
Counter
对象。如果不提供参数,count
将默认被初始化为 0。
-
-
前置
++
运算符重载:Counter& operator++() { ++count; return *this; } // ++c1;
-
这是前置自增运算符的重载。前置自增先增加对象的
count
值,然后返回对象本身的引用(即*this
)。 -
返回引用的原因是为了支持连续的操作,如
++(++c1);
。
-
-
后置
++
运算符重载:Counter operator++(int) { Counter temp = *this; ++count; return temp; } // c1++;
-
这是后置自增运算符的重载。后置自增需要传递一个整型参数
int
,用于区分它与前置自增运算符。该参数并不实际使用。 -
后置自增首先将当前对象的状态保存到
temp
中,然后增加count
的值,最后返回未自增前的对象temp
。
-
-
显示当前计数值:
void display() const { std::cout << "Count: " << count << std::endl; }
-
这个成员函数输出当前计数器的值。函数末尾的
const
表示该函数不会修改类的成员变量。
-
-
在
main
函数中的使用:-
首先,创建了一个初始值为 5 的
Counter
对象c1
。 -
使用
++c1
触发前置自增运算符。count
值从 5 增加到 6,并显示结果。 -
使用
c1++
触发后置自增运算符。count
值先从 6 增加到 7,然而返回的是未增加前的状态。因此显示的结果仍然是6
。在显示完成后,count
实际上已变为7
。
-
3. 重载运算符的注意事项
运算符必须是类的成员函数或友元函数
有些运算符必须作为成员函数实现,如
=
、[]
、()
和->
。而有些运算符可以作为友元函数来实现,如
+
、-
等。不能重载的运算符
有一些运算符是不能重载的,包括
::
(作用域解析运算符)、.
(成员访问运算符)、.*
(成员指针访问运算符)、?:
(条件运算符)和sizeof
(类型大小运算符)。
4. 重载运算符时的规则
保持运算符的语义一致性
重载运算符时应尽量保持其原有的语义。
例如,重载
+
运算符时,应该实现对象之间的“加法”行为。返回类型
运算符重载的返回类型取决于运算符的类型和预期的操作结果。
可以返回对象、引用或指针。
成员函数与友元函数的选择
成员函数一般用于需要访问对象内部数据的运算符
友元函数则用于需要同时访问两个对象内部数据的运算符。
三、扩展
问题1:如何区分对象创建时,调用的是构造函数还是赋值重载函数?
在 C++ 中,区分构造函数和赋值操作符是根据它们在对象生命周期中的作用和调用方式来实现的。
1. 构造函数
作用:用来初始化新创建的对象。
调用方式:在创建对象时调用,例如
String string3 = string1;
。
2. 赋值操作符
作用:用来将一个已存在的对象的值赋给另一个已存在的对象。
调用方式:在对象已经创建并且已被初始化之后,调用赋值操作符,例如
string4 = string1;
。
示例解析
构造函数
String string3 = string1;
这行代码在创建
string3
对象时直接调用了构造函数。这里使用了拷贝构造函数,因为
string3
是新创建的对象,string1
是一个已经存在的对象。
赋值操作符
String string4;
string4 = string1;
-
这两行代码首先创建了
string4
对象(使用默认构造函数),然后将string1
的值赋给string4
。
关键区别
标签:函数,int,C++,运算符,++,Complex,重载 From: https://blog.csdn.net/m0_63956046/article/details/141649128
创建与赋值
构造函数用于创建并初始化对象
赋值操作符用于给已存在的对象赋值。
调用时机
String string3 = string1;
是在string3
创建时发生的,调用了拷贝构造函数
string4 = string1;
是在string4
已存在后发生的,调用了赋值操作符。