目录
运算符重载
1.概念
C++中可以把部分的运算符开做成函数,此时运算符也可以重载。
运算符预定义的操作只能针对基本数据类型。但是对于自定义类型,也需要类似运算操作,此时就可以重新定义这些运算符的功能,使其支持特定类型,完成特定的操作。
可以被重载的运算符:算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不被重载的运算符:
成员运算符"."、指针运算符"*"、三目运算符" ? : "、sizeof、作用域"::"
运算符重载有两种实现方式:
1.友元函数运算符重载
2.成员函数运算符重载
2.友元函数运算符重载
cpp
#include <iostream>
using namespace std;
class MyInt
{
private:
int a;
public:
MyInt(int a)
{
this->a=a;
}
int get_int()
{
return a;
}
friend MyInt operator +(MyInt &i,MyInt &i2);
friend MyInt operator ++(MyInt &i);//前置++
friend MyInt operator ++(MyInt &i,int);//后置++
};
MyInt operator +(MyInt &i,MyInt &i2)
{
return i.a+i2.a;
}
MyInt operator ++(MyInt &i)
{
return ++i.a;
}
MyInt operator ++(MyInt &i,int)
{
return i.a++;
}
int main()
{
MyInt int1(1);
MyInt int2(2);
MyInt int3=int1+int2;
cout<<"int1: "<<int1.get_int()<<endl;
cout<<"int2: "<<int2.get_int()<<endl;
cout<<"int3=int1+int2"<<endl;
cout<<"++int3: "<<(++int3).get_int()<<endl;
cout<<"int3++: "<<(int3++).get_int()<<endl;
cout<<"int3: "<<int3.get_int()<<endl;
return 0;
}
3.成员函数运算符重载
成员函数运算符重载相比于友元函数运算符重载,最主要的区别,在于友元函数的第一个输入参数,在成员函数中使用this指针代替,因此同样的运算符重载,成员函数比友元函数参数少一个。
cpp
#include <iostream>
using namespace std;
class MyInt
{
private:
int a;
public:
MyInt(int a)
{
this->a=a;
}
int get_int()
{
return a;
}
MyInt operator +(MyInt &i);
MyInt operator ++();//前置++
MyInt operator ++(int);//后置++
};
MyInt MyInt::operator +(MyInt &i)
{
return this->a+i.a;
}
MyInt MyInt::operator ++()
{
return ++this->a;
}
MyInt MyInt::operator ++(int)
{
return this->a++;
}
int main()
{
MyInt int1(1);
MyInt int2(2);
MyInt int3=int1+int2;
cout<<"int1: "<<int1.get_int()<<endl;
cout<<"int2: "<<int2.get_int()<<endl;
cout<<"int3=int1+int2"<<endl;
cout<<"++int3: "<<(++int3).get_int()<<endl;
cout<<"int3++: "<<(int3++).get_int()<<endl;
cout<<"int3: "<<int3.get_int()<<endl;
return 0;
}
4.特殊运算符重载
1.赋值运算符重载
除了之前学习的无参构造函数、拷贝构造函数、析构函数以外,如果程序员不手写,编译器还会添加一个赋值运算符重载函数。
赋值运算符重载只能使用成员函数运算符实现。
当类中出现指针类型的成员变量时,默认的赋值运算符重载函数,类似于默认的浅拷贝构造函数,因此需要手动编写解决"浅拷贝"的问题。
cpp
#include <iostream>
using namespace std;
class MyInt
{
int a;
public:
MyInt(int a)
{
this->a=a;
}
int get_int()
{
return a;
}
MyInt &operator =(MyInt &i)
{
cout<<"调用赋值运算符重载函数"<<endl;
this->a=i.a;
return *this;
}
};
int main()
{
MyInt int1(1);
MyInt int2(2);
cout<<"int1: "<<int1.get_int()<<endl;
cout<<"int2: "<<int2.get_int()<<endl;
int2=int1;
cout<<"int2: "<<int2.get_int()<<endl;
return 0;
}
2.类型转换运算符重载
必须使用成员函数运算符重载,且格式比较特殊。
cpp
#include <iostream>
using namespace std;
class MyInt
{
int a;
string b="hello";
public:
MyInt(int a)
{
this->a=a;
}
operator int()
{
return a;
}
operator string()
{
return b;
}
};
int main()
{
MyInt int1(1);
int a=int1;
string b=int1;
cout<<"int a = "<<a<<endl;
cout<<"string b = "<<b<<endl;
return 0;
}
5.注意事项
1.重载的运算符限制在C++语言中已有的运算符范围,不能创建新的运算符。
2.运算符重载本质上也是函数重载,但是不支持函数默认值设定。
3.重载之后运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数和语法结构。
4.运算符重载必须基于或包含自定义类型,即不能改变基本数据类的运算规则。
5.重载的功能应该与原有的功能相似,避免没有目的的滥用运算符重载。
6.一般情况下,双目运算符建议使用友元函数运算符重载,单目运算符建议使用成员函数运算符重载。
std::string字符串类:
字符串对象是一种特殊类型的容器,专门设计用于操作字符串。
cpp
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
string s;
// 判断是否为空
cout<<s.empty()<<endl; //1
string s1="hello";//隐式调用构造函数
cout<<s1<<endl; //hello
string s2("world");//显式调用构造函数
cout<<s2<<endl; //world
//==、!=、> 、< 判断
cout<<(s1==s2)<<endl; //0
cout<<(s1!=s2)<<endl; //1
cout<<(s1>s2)<<endl; //0
cout<<(s1<s2)<<endl; //1
string s3(s2);//拷贝构造函数
cout<<s3<<endl; //world
// 参数1:char * 源字符串
// 参数2:保留的字符串数
string s4("ABCDE",3);
cout<<s4<<endl; //ABC
// 参数1:std::string 源字符串
// 参数2:不保留的字符数,从头开始
string s5(s2,3);
cout<<s5<<endl; //ld
// 参数1:字符数量
// 参数2:字符内容 char
string s6(5,'a');
cout<<s6<<endl; //aaaaa
cout << "原s5 = " << s5 << " " << "原s6 = " << s6 << endl;
swap(s5,s6); // 交换
cout << "交换后s5 = " << s5 << " " << "交换后s6 = " << s6 << endl;
string s7=s1+s2;//字符串连接
cout<<s7<<endl; //helloworld
s7.append("你好世界");// 向后追加字符串
cout<<s7<<endl; //helloworld你好世界
s7.push_back('a');// 向后追加单个字符
cout<<s7<<endl; //helloworld你好世界a
// 插入
// 参数1:插入的位置
// 参数2:插入的内容
s7.insert(0,"123");
cout<<s7<<endl; //123helloworld你好世界a
// 删除字符串
// 参数1:起始位置
// 参数2:删除的字符数量
s7.erase(2,5);
cout<<s7<<endl; //12oworld你好世界a
// 替换
// 参数1:起始位置
// 参数2:被替换的字符数
// 参数3:替换的新内容
s7.replace(0,3,"++++");
cout<<s7<<endl; //++++world你好世界a
s7.clear(); // 清空
cout<<s7.length()<<endl; //0
string s8="heiheihei";
cout<<s8<<endl; //heiheihei
s8="ABCDEFG"; // 重新赋值
cout<<s8<<endl; //ABCDEFG
// 参数1:拷贝的目标
// 参数2:拷贝的字符数量
// 参数3:拷贝的起始位置
// C++的string到C语言数组
char a[20]={0};
s8.copy(a,3,0);
cout<<a<<endl; //ABC
// C++ string 到 c string 用到了C语言中的strcpy
// c_str C++的字符串转成C语言的字符数组
// c_str 返回一个 const char *
char b[20]={0};
strcpy(b,s8.c_str());
cout<<b<<endl; //ABCDEFG
return 0;
}
模板与容器
模板
模板可以让类或者函数支持一种通用类型,这种通用类型在实际运行的过程中可以使用任何数据类型,因此可以写一些与类型无关的代码,这种编程方式也被称为"泛型编程"。
通常有两种形式:
1.函数模板
2.类模板
1.函数模板
使一个函数支持模板编程,可以使函数支持通用数据类型。
cpp
#include <iostream>
using namespace std;
template<typename T> // typename也可以是class
T add(T a,T b)
{
return a + b;
}
int main()
{
string str1 = "hello";
string str2 = "world";
cout << add(str1,str1) << endl;
return 0;
}
2.类模板
使一个类支持模板编程,可以使一个类支持通用数据类型。
类内实现
cpp
#include <iostream>
using namespace std;
template<class T>
class Test
{
private:
T val;
public:
Test(T v)
{
val = v;
}
T get_val()const
{
return val;
}
void set_val(const T &val)
{
this->val = val;
}
};
int main()
{
Test<int> t1(20);
cout << t1.get_val() << endl;
t1.set_val(10);
cout << t1.get_val() << endl;
t1.set_val(10.32);
cout << t1.get_val() << endl; // 数据窄化10
Test<double> t2(2.56);
cout << t2.get_val() << endl;
t2.set_val(23.12);
cout << t2.get_val() << endl;
return 0;
}
类内声明类外实现
cpp
#include <iostream>
using namespace std;
template<class T>
class Test
{
private:
T val;
public:
Test(T v);
T get_val()const;
void set_val(const T &val);
};
template<class T>
Test<T>::Test(T v)
{
val = v;
}
template<class T>
T Test<T>::get_val()const
{
return val;
}
template<class T>
void Test<T>::set_val(const T &val)
{
this->val = val;
}
int main()
{
Test<int> t1(20);
cout << t1.get_val() << endl;
t1.set_val(10);
cout << t1.get_val() << endl;
t1.set_val(10.32);
cout << t1.get_val() << endl; // 数据窄化10
Test<double> t2(2.56);
cout << t2.get_val() << endl;
t2.set_val(23.12);
cout << t2.get_val() << endl;
return 0;
}