目录
继续C++ ------3
||
++操作符的友元函数重载
#include <iostream>
using namespace std;
class Integer{ //整数类
private:
int value;
public:
Integer(int v):value(v){}
friend Integer operator ++(Integer &i2);
friend Integer operator ++(Integer &i2,int);
void show(){
cout<<value<<endl;
}
};
Integer operator ++(Integer &i2){ //前置++
cout<<"前置++"<<endl;
//值先加 再返回
i2.value++;
Integer temp(i2.value);
return temp;
//也可以用以下方法:
//i2.value++;
//return i2;
}
Integer operator ++(Integer &i2,int){ //后置++
cout<<"后置++"<<endl;
//先返回旧值,然后再++
Integer temp(i2.value); //对象的旧值
i2.value++;
return temp;
}
int main(){
Integer i2(10);
(i2++).show(); //10
i2.show(); //11
(++i2).show(); //12
}
++操作符的成员函数重载
#include <iostream>
using namespace std;
class Integer{ //整数类
private:
int value;
public:
Integer(int v):value(v){}
Integer operator ++();
Integer operator ++(int);
void show(){
cout<<value<<endl;
}
};
Integer Integer::operator ++(){ //前置++
cout<<"前置++"<<endl;
//值先加 再返回
this->value++;
return *this; //因为this本身是个特殊的指针,所以加*取this指针的内容
}
Integer Integer::operator ++(int){ //后置++
cout<<"后置++"<<endl;
//先返回旧值,然后再++
Integer temp(this->value); //对象的旧值
this->value++;
return temp;
}
int main(){
Integer i2(10);
(i2++).show(); //10
i2.show(); //11
(++i2).show(); //12
}
赋值运算符重载
作用:用一个对象的值改变另一个对象的值
格式:T&operator=(const T& other) //T可以任意类型
特点:是类内函数,只支持成员函数重载。
如果不显示给出赋值运算符函数,会有一个默认的赋值运算符函数。
如果当类中的属性有指针类型的时候,默认的赋值运算符函数也会引发浅拷贝问题,这时需要给出赋值运算符重载的实现。
#include <iostream>
using namespace std;
class Integer{
private:
int value;
public:
Integer(int v):value(v){}
//T& operator=(const T& other)
Integer& operator=(const Integer& t3){
cout<<"赋值运算符重载"<<endl;
this->value=t3.value;
}
void show(){
cout<<value<<endl;
}
};
int main(){
Integer i2(10);
Integer i3(20);
i2 = i3;
i2.show();
}
类型转换运算符
目的:可以使自定义类型转成任意类型
特点:只支持成员函数重载
#include <iostream>
using namespace std;
class Integer{
private:
int value;
string str;
public:
explicit Integer(int v,string s):value(v),str(s){}
void show(){
cout<<value<<endl;
}
operator int(){ //把类中int类型的value返回出来
return value;
}
operator string(){ //把类中string类型的str返回出来
return str;
}
};
int main(){
Integer i2(10,"tom");
//Integer i3=10,tom; explicit 屏蔽隐藏调用函数 行不通
int a=i2;
cout<<a<<endl;
string s=i2;
cout<<s<<endl;
}
运算符重载注意事项
可以被重载的运算符:
算术运算符:+、-、*、/、%、++、--
位操作运算符:&、|、~、^(位异或)、<<(左移)、>>(右移)
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]
不被重载的运算符:
成员运算符 .、指针运算符 *、三目运算符 ? :、sizeof、作用域 ::
●运算符重载限制在C++已有的运算符范围内,不允许创建新的运算符。
●运算符重载也是函数重载,运算符也是函数。
●重载之后的运算符不能改变优先级和结合性。
●重载之后的运算符不能改变操作数和语法结构。
●运算符重载不能改变该运算符用于基本数据类型的含义,但是可以把基本数据类型与自定义类型一起运算,或者都使用自定义类型。
●运算符重载是针对新类型数据的实际需要对原有运算符的功能进行扩充,因此重载之后的功能应该与原有的功能类似,避免没有目的地使用运算符重载。
string类
增、删、改、插入、比较、等操作。。。
#include <iostream>
using namespace std;
int main(){
string s1; //创建一个没有的字符
string s2="AAA"; //相当于调用隐式构造函数
string s3("BBB");
//增
string s4=s2+s3;
cout<<s4<<endl; //AAABBB
s4.append("CCC");
cout<<s4<<endl; //AAABBBCCC
//删
//第一个参数为起始位置、第二个参数为个数
s4.erase(3,3); //AAACCC
cout<<s4<<endl;
//改
s4[0]='Q'; //不用at超出范围不会报错
cout<<s4<<endl; //QAACCC
s4.at(0)='W'; //at超出范围会报错,at更安全
cout<<s4<<endl; //WAACCC
//插入
s4.insert(1,"DDD");
cout<<s4<<endl; //WDDDAACCC
//替换
//参数:
//第一个参数为替换的起始位置、第二个参数为替换的个数、第三个参数为新的内容
s4.replace(1,3,"TomCat");
cout<<s4<<endl; //WTomCatAACCC
//比较运算符 > < == !=
//string类型 默认比较的是编码
string s5="hello";
string s6="hellp";
cout<<"s5>s6:"<<(s5>s6)<<endl; //0 比较的是编码false
//c++中有专门表示 对 或者 错 ,用bool类型,正确返回TRUE 就是1.否则返回FLOSE 就是0
bool b=(s5>s6);
cout<<b<<endl; //0
//size() length()都可以得到字符串长度
cout<<( s5.size()==s6.size() )<<endl; //1
//遍历,需要c++11支持 QMAKE_CXXFLAGS += -std=c++11
for(char ch:s5){
cout<<ch<<" ";
}
}
bool类型的练习
#include <iostream>
using namespace std;
bool metod(int a,int b){
//a大于b r的值为1,否则为0
bool r=(a>b);
return r;
//或者直接返回 比较结果
//return a>b;
}
int main(){
int m=80,n=30;
bool re= metod(m,n);
if(re==1){
cout<<"m的值大于n的值"<<endl;
}else{
cout<<"m的值小于n的值"<<endl;
}
}
模板
c++使用模板可以实现参数的多态化。可以让类函数声明一种通用的形式,使函数或类实现不需要具体数据类型
模板:
1.函数模板
#include <iostream>
using namespace std;
//不使用模板:
//void mySwap(int& m,int& n){
// int t=m;
// m=n;
// n=t;
//}
//void mySwap(char& m,char& n){
// int t=m;
// m=n;
// n=t;
//}
//交换模板:
template <typename T>
void mySwap(T& m,T& n){
T t=m;
m=n;
n=t;
}
class Person{
private:
string name;
public:
Person(string n):name(n){}
void show(){
cout<<name<<endl;
}
};
int main(){
int a=20;
int b=30;
mySwap(a,b);
cout<<a<<" "<<b<<endl;
char ch1='A';
char ch2='B';
mySwap(ch1,ch2);
cout<<ch1<<" "<<ch2<<endl;
Person tang("唐僧");
Person monkey("孙悟空");
mySwap(tang,monkey);
tang.show();
monkey.show();
}
注意:
1.每次新的模板,模板需重新写明
2.typename和class都可以做模板形参修饰。函数模板通常用typename, 类模板用class。
3.实参类型不同时,模板形参的类型也需要不同
#include <iostream>
using namespace std;
template <typename T> //每次新的模板 声明需要重新写明
void mySwap(T& m,T& n){
T t=m;
m=n;
n=t;
}
template <typename T,typename T2>
//template <class T,class T2>
void add(T& m,T2& n){
cout<<m+n<<endl;
}
int main(){
int a=95,c=75;
char b='A';
add(a,b);
add(a,c);
}
2.类模板
不能通过实参类型,自动识别。需要在<>指明参数的实际类型
Dome<string,int> student("小强",20);
#include <iostream>
using namespace std;
template <class T,class T2>
class Demo{
private:
T value1;
T2 value2;
public:
// Demo(T n,T2 v){
// value1=n;
// value2=v;
// }
Demo(T n, T2 v):value1(n),value2(v){}
void show(){
cout<<value1<<" "<<value2<<endl;
}
};
int main(){
//不能通过实参类型自动转换
Demo<string,int> student("小强",20);
student.show();
Demo<int,int> rectangle(20,30);
rectangle.show();
}
练习:Compare的类模板
有两个私有属性 t1和t2类型相同
myMax方法可以得出 t1和t2 中的最大的值
myMin方法可以得出 t1和t2 中的最小的值
Compare<int>(5,8)c1;
c1.myMax()可以得到8
我的方法:
#include <iostream>
using namespace std;
template <class T>
class Compare{
private:
T value;
T value2;
public:
Compare(T m,T n):value(m),value2(n){}
void myMax(){
if(value>value2){
cout<<"Max: "<<value<<endl;
}else{
cout<<"Max: "<<value2<<endl;
}
}
void myMin(){
if(value2<value){
cout<<"Min: "<<value2<<endl;
}else{
cout<<"Min: "<<value<<endl;
}
}
};
int main(){
Compare<int> c1(5,8);
c1.myMax();
c1.myMin();
Compare<string> c2("hello","hellp");
c2.myMax();
c2.myMin();
}
讲师方法:
#include <iostream>
using namespace std;
template <class T> //每次新的模板 声明需重名写明
class Compare{
private:
T t1;
T t2;
public:
Compare(T n,T v){
t1=n;
t2=v;
}
T myMax(){
if(t1>t2){
return t1;
}else{
return t2;
}
}
T myMin(){
return t1<t2?t1:t2;
}
};
int main()
{
Compare<int>c1(5,8);
cout<<"myMax():"<<c1.myMax()<<endl;
cout<<"myMin():"<<c1.myMin()<<endl;
Compare<string>c2("hello","hellp");
cout<<c2.myMax()<<endl; //hellp
cout<<c2.myMin()<<endl; //hello
}
模板类成员函数声明和定义分离
1.每个函数都需要加上模板和声明
2.需要用类名<>::的方式做作用域限定符。指明它时模板类的函数
#include <iostream>
using namespace std;
//每次新的模板 声明需重名写明
template <class T>
class Compare{
private:
T t1;
T t2;
public:
Compare(T n,T v);
T myMax();
T myMin();
};
template <class T>
Compare<T>::Compare(T n,T v){
t1=n;
t2=v;
}
template <class T>
T Compare<T>::myMax(){
if(t1>t2){
return t1;
}else{
return t2;
}
}
template <class T>
T Compare<T>::myMin(){
return t1<t2?t1:t2;
}
int main()
{
Compare<int>c1(5,8);
cout<<"myMax():"<<c1.myMax()<<endl;
cout<<"myMin():"<<c1.myMin()<<endl;
Compare<string>c2("hello","hellp");
cout<<c2.myMax()<<endl; //hellp
cout<<c2.myMin()<<endl; //hello
}
泛型编程与STL
(熟悉)
泛型编程提出的目的是:发明一种语言机制,能够实现一个标准的容器库(标准模板库 STL),标准容器库可以做到编写一般化的算法,来支持不同的数据类型。
标准模板库(STL)是美国的惠普实验室开发的一系列软件的统称,后来被引入到C++语言中,主要包括:
- 算法 sort()
- 容器 : 存放数据的类模板
- 迭代器:指示元素位置,方便算法访问操作容器
在STL中,几乎所有的代码都采用了模板来实现,相比于传统的库,具有更好的适用性和重用性。
容器:顺序容器、关联容器
顺序容器:元素之间是顺序关系
关联容器:元素之间没有严格物理上的顺序关系,内部是有联系的
顺序容器:Array数组,vector向量,list双向链表
关联容器:map 键值对 ,mulitmap 多重键值对
Array数组
c++11引入的数组。更安全和易于使用
#include <iostream>
#include <array>
using namespace std;
int main(){
array <int,5> a; //没有赋值,为随机值
array <int,20>b={10,20,30};
//前三个有赋值,后面未赋值的部分是默认值0
for(int i:b){
cout<<i<<" ";
}cout<<endl;
array <string,3> str={"AA","BB","CC"};
str[0]="hello";
cout<<"str.at(0):"<<str.at(0)<<endl; //hello
for(string i:str){
cout<<i<<endl;
}
}
vector向量
vector向量容器是一种支持高效的随机访问和高效尾部插入新元素的容器。
向量容器一般实现为一个动态分配的数组,向量中的元素连续地存放在这个数组中
因此对向量容器进行随机访问,具有和动态访问数组类似的效率。
向量容器具有扩展容器的功能,当数组的空间不够时,向量容器对象会自动new一块更大的空间,
使用赋值运算符将原有的数据复制到新空间,并将原有空间释放。因此向量容器在每次扩展空间时,实际分配的空间一般大于所需的空间
可以高效的访问,但是插入和删除效率偏低
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v; //长度为0,空的字符串
cout<<v.empty()<<endl;//返回值bool类型 返回1 为空
vector<int> v2(5); //长度为5 默认值为0
cout<<v2.empty()<<endl; //0
vector<string> v3(5); //默认空字符串
vector<int> v4(10,1); //10个全为1
vector<string> v5={"AA","BB","CC"};
vector<int> v6(v4);
for(int i:v2){
cout<<i<<" ";
}cout<<endl; //0 0 0 0 0
for(string i:v3){
cout<<i<<" ";
}cout<<endl; //空
for(int i:v4){
cout<<i<<" ";
}cout<<endl; //1 1 1 1 1 1 1 1 1 1
for(string i:v5){
cout<<i<<" ";
}cout<<endl; //AA BB CC
for(int i:v6){
cout<<i<<" ";
}cout<<endl; //1 1 1 1 1 1 1 1 1 1
}
方法
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> v; //空的
//尾部追加
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);//1 2 3 4
//尾部删除
v.pop_back();//1 2 3 删除了最尾端的4
//得到尾部和首部元素
cout<<v.front()<<endl; //1
cout<<v.back()<<endl; //3
//随机取和修改
cout<<v[1]<<endl; //2
cout<<v.at(1)<<endl; //2
v.at(0)=5; //5 2 3
//插入
//v.begin() 返回第一个元素的位置
//v.end() 返回最后一个元素的位置
v.insert(v.begin(),4); //4 5 2 3
v.insert(v.end(),99); //4 5 2 3 99
//end 指向元素最后一位的后面 即 3后面
//删除
v.erase(v.begin()+2); //4 5 3 99
//清空
v.clear();
for(int i:v){
cout<<i<<" ";
}
}