文章目录

  • ​​一 运算符重载​​
  • ​​1.1 概念​​
  • ​​1.2 运算符重载的规则​​
  • ​​(1)不能重载的运算符​​
  • ​​(2) 重载不能改变运算符的优先级和结合性​​
  • ​​(3) 重载不能概念运算符的用法(即不能改变其操作数)​​
  • ​​(4) 运算符重载不能有默认参数,否则会改变运算符的操作数​​
  • ​​1.3 重载的步骤​​
  • ​​1.4 重载输出运算符​​
  • ​​1.5 单目运算符的重载​​
  • ​​1.6 逻辑运算符的重载​​
  • ​​1.7 数组类​​
  • ​​练习:自己实现string类(字符串类)​​
  • ​​二 模板​​
  • ​​2.1 函数模板​​
  • ​​2.2 函数模板的实现机制​​
  • ​​笔试题​​

一 运算符重载

1.1 概念

所谓重载,就是重新赋予运算符新的含义,运算符重载使得同一个运算符,具有不同的功能
运算符重载的本质就是函数的重载。
#include <iostream>
using namespace std;
class Complex
{
//friend Complex operator+(const Complex &c1,const Complex &c2);
private:
int a; //实部
int b; //虚部
public:
Complex(int _a,int _b)
{
this->a = _a;
this->b = _b;
}
void print()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
Complex operator+(const Complex &c)
{
Complex t(0,0);
t.a = this->a + c.a;
t.b = this->b + c.b;
return t;
}
};
/*Complex operator+(const Complex &c1,const Complex &c2)
{
Complex t(0,0);
t.a = c1.a + c2.a;
t.b = c1.b + c2.b;
return t;
}*/
int main(int argc, char const *argv[])
{
Complex c1(1,2);
Complex c2(2,3);
Complex c(0,0);
c = c1 + c2; //c = c1.operator+(c2);
c.print();
return 0;
}

1.2 运算符重载的规则

(1)不能重载的运算符

:: ?: . .* sizeof

(2) 重载不能改变运算符的优先级和结合性

c4 = c1 + c2 * c3;
等价于:c4 = c1 + (c2 * c3);

(3) 重载不能概念运算符的用法(即不能改变其操作数)

(4) 运算符重载不能有默认参数,否则会改变运算符的操作数

1.3 重载的步骤

1.写出函数名称。
2.根据操作数写出函数的形参。
3.根据使用场景写出函数的返回值类型。
4.完成函数体。

1.4 重载输出运算符

#include <iostream>
using namespace std;
class Complex
{
friend ostream& operator<<(ostream &out,const Complex &c);
//friend Complex operator+(const Complex &c1,const Complex &c2);
private:
int a; //实部
int b; //虚部
public:
Complex(int _a,int _b)
{
this->a = _a;
this->b = _b;
}
void print()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
Complex operator+(const Complex &c)
{
Complex t(0,0);
t.a = this->a + c.a;
t.b = this->b + c.b;
return t;
}
/*ostream& operator<<(ostream &out)
{
out<<this->a<<"+"<<this->b<<"i";
return out;
}*/
};
ostream& operator<<(ostream &out,const Complex &c)
{
out<<c.a<<"+"<<c.b<<"i";
return out;
}
int main(int argc, char const *argv[])
{
Complex c1(1,2);
//c1.print();
cout<<c1<<endl; //operator<<(operator<<(cout,c1),endl);
return 0;
}

1.5 单目运算符的重载

++ --
#include <iostream>
using namespace std;
class Complex
{
friend ostream& operator<<(ostream &out,const Complex &c);
//friend Complex operator+(const Complex &c1,const Complex &c2);
private:
int a; //实部
int b; //虚部
public:
Complex(int _a,int _b)
{
this->a = _a;
this->b = _b;
}
void print()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
Complex operator+(const Complex &c)
{
Complex t(0,0);
t.a = this->a + c.a;
t.b = this->b + c.b;
return t;
}
//前置++
Complex operator++()
{
this->a++;
this->b++;
return *this;
}
//后置++
Complex operator++(int) //通过占位参数来构成函数重载
{
Complex t = *this;
this->a++;
this->b++;
return t;
}
/*ostream& operator<<(ostream &out)
{
out<<this->a<<"+"<<this->b<<"i";
return out;
}*/
};
ostream& operator<<(ostream &out,const Complex &c)
{
out<<c.a<<"+"<<c.b<<"i";
return out;
}
int main(int argc, char const *argv[])
{
Complex c1(1,2);
cout<<++c1<<endl;
cout<<c1++<<endl;
cout<<c1<<endl;
return 0;
}

1.6 逻辑运算符的重载

&&: c1 && c2
||: c1 || c2
#include <iostream>
using namespace std;
class Complex
{
friend ostream& operator<<(ostream &out,const Complex &c);
//friend Complex operator+(const Complex &c1,const Complex &c2);
private:
int a; //实部
int b; //虚部
public:
Complex(int _a,int _b)
{
this->a = _a;
this->b = _b;
}
void print()
{
cout<<a<<"+"<<b<<"i"<<endl;
}
Complex operator+(const Complex &c)
{
Complex t(0,0);
t.a = this->a + c.a;
t.b = this->b + c.b;
return t;
}
//前置++
Complex operator++()
{
this->a++;
this->b++;
return *this;
}
//后置++
Complex operator++(int) //通过占位参数来构成函数重载
{
Complex t = *this;
this->a++;
this->b++;
return t;
}
bool operator&&(const Complex &c)
{

}
/*ostream& operator<<(ostream &out)
{
out<<this->a<<"+"<<this->b<<"i";
return out;
}*/
};
ostream& operator<<(ostream &out,const Complex &c)
{
out<<c.a<<"+"<<c.b<<"i";
return out;
}
int main(int argc, char const *argv[])
{
Complex c1(1,1);
Complex c2(2,2);
Complex c3(0,0);
if(c1 && c2)
{
cout<<"成立"<<endl;
}
if(c3 && c1++ +c2++) //operator&&(c3,operator+(c1,c2)) //重载的时候不要重载逻辑运算符&& ||,因为违背了短路原则
{

}
return 0;
}

1.7 数组类

#include <iostream>
using namespace std;
class Array
{
private:
int size;
int *data;
public:
Array(int s)
{
size = s;
data = new int[size];
}
int& operator[](int Index)
{
return data[Index];
}
bool operator==(const Array &a)
{
/*
if(this->size != a.size)
{
return false;
}
for(int i = 0; i < size;i++)
{
if(this->data[i] != a.data[i])
{
return false;
}
}
return true;
*/
return (this->data == a.data && this->size == a.size);
}
Array& operator=(const Array &a)
{
if(*this == a)
{
return *this;
}
/*if(this == &a)
{
return *this;
}*/
this->size = a.size;
delete this->data;
this->data = new int[size];
for(int i = 0; i< size;i++)
{
this->data[i] = a.data[i];
}
}
~Array()
{
if(data != NULL)
{
delete []data;
}
}
};

int main(int argc, char const *argv[])
{
Array a1(10); //创建数组对象
a1[0] = 100;
for(int i = 0; i < 10;i++)
{
a1[i] = i + 10;
}
for(int i = 0; i < 10;i++)
{
cout<<a1[i]<<" ";
}
cout<<endl;

Array a2(5);
//a1 = a2;
a1 = a1;
for(int i = 0 ; i< 10;i++)
{
cout<<a1[i]<<" ";
}
cout<<endl;
return 0;
}

练习:自己实现string类(字符串类)

#include <iostream>
#include <cstring>
using namespace std;
class MyString
{
public:
MyString();
MyString(const char *str);
MyString(const MyString &obj);
char& operator[](int index);
MyString& operator=(const char *str);
MyString& operator+(const char *str);
MyString& operator+(const MyString &str);
bool operator==(const MyString &obj);
void show();
private:
char *pstring;
int m_size;
};
void MyString::show()
{
cout<<"string = "<<pstring<<endl;
}
MyString::MyString()
{
this->m_size = 0;
this->pstring = NULL;
}
MyString::MyString(const char *str)
{
m_size = strlen(str) + 1;
this->pstring = new char[m_size];
strcpy(this->pstring,str);
}
MyString::MyString(const MyString &obj)
{
this->m_size = obj.m_size;
this->pstring = new char[m_size];
strcpy(this->pstring,obj.pstring);
}
char& MyString::operator[](int index)
{
static char ch =-1;
if(index >=0 && index < this->m_size)
{
return this->pstring[index];
}
else
{
printf("越界操作了\n");
return ch;
}
}
MyString& MyString::operator=(const char *str)
{
this->m_size = strlen(str) + 1;
if(this->pstring != NULL)
{
delete []this->pstring;
this->pstring = new char[m_size];
}
else
{
this->pstring = new char[m_size];
}
strcpy(this->pstring,str);
return *this;
}
MyString& MyString::operator+(const char *str)
{
if(this->pstring != NULL)
{
char *s = new char[this->m_size + 1];
strcpy(s,this->pstring);
delete []this->pstring;
this->pstring = new char[this->m_size + strlen(str) + 1];
stpcpy(this->pstring,s);
strcat(this->pstring,str);
this->m_size += strlen(str);
delete []s;
}
else
{
this->pstring = new char[strlen(str) + 1];
this->m_size = strlen(str);
strcpy(this->pstring,str);
}
return *this;
}
MyString& MyString::operator+(const MyString &str)
{
if(this->pstring != NULL)
{
char *s = new char[this->m_size + 1];
strcpy(s,this->pstring);
delete []this->pstring;
this->pstring = new char[this->m_size + str.m_size + 1];
stpcpy(this->pstring,s);
strcat(this->pstring,str.pstring);
this->m_size += str.m_size;
delete []s;
}
else
{
this->pstring = new char[str.m_size + 1];
this->m_size = str.m_size;
strcpy(this->pstring,str.pstring);
}
return *this;
}
bool MyString::operator==(const MyString &obj)
{
if(strcmp(this->pstring,obj.pstring) == 0)
{
return true;
}
else
{
return false;
}
}
int main(int argc, char const *argv[])
{
MyString m1("hello world");
m1.show();
MyString m2(m1);
m2.show();

cout<<m2[3]<<endl;
cout<<m2[0]<<endl;

m2 = "nihao beijing";
m2.show();

MyString m3;
m3 = m2 = m1;
m1.show();
m2.show();
m3.show();

cout<<"***************"<<endl;
MyString m4("nihao");
m4 = m4 + "helloworld";
m4.show();

MyString m5("hahahah");
m5 = m5 + m4;
m5.show();

if(m5 == m4)
{
cout<<"m5 = m4"<<endl;
}
else
{
cout<<"m5 != m4"<<endl;
}

return 0;
}

二 模板

泛型编程,通过建立一个通用的函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来表示,这个通用的函数就是函数模板。

2.1 函数模板

template <类型形式参数表>
类型 函数名<形式参数表>
{
语句块
}
#include <iostream>
using namespace std;
/*int add(int x,int y) //int y = 'a'
{
cout<<"int add(int x,int y)"<<endl;
return x + y;
}
double add(double x,double y)
{
cout<<"double add(double x,double y)"<<endl;
return x + y;
}*/

template <typename T>
T add (T x, T y)
{
cout<<"T add (T x, T y)"<<endl;
return x + y;
}

template<typename T1,typename T2>
void print(T1 x,T2 y)
{
cout<<x<<" "<<y<<endl;
}
int main(int argc, char const *argv[])
{
cout<<add(1,2)<<endl; //隐式调用
//当模板函数和普通函数同时存在,优先调用普通函数

cout<<add<int>(1,'a')<<endl;//显示调用
//模板函数不能进行隐式类型转换
print(1,'a');
print<double,char>(1.11,'a');
return 0;
}

2.2 函数模板的实现机制

实现机制:二次编译/延迟编译:第一次看到模板函数定义的位置时,编译时只检查基本语法错误,不检查数据类型的错误,使用模板函数实例化对象时,看到模板函数之后根据传递的模板实参再检查类型的错误,这种编译方法称为二次编译。

笔试题

#include <stdio.h>

struct test{
int a;
int b;
};
void func(struct test *tt)
{
struct test *lt;
lt = &tt[0];
printf("[0]a:%d,b: %d\n",lt->a,lt->b);
lt = &tt[1];
printf("[1]a:%d,b: %d\n",lt->a,lt->b);
lt = &tt[2];
printf("[2]a:%d,b: %d\n",lt->a,lt->b);

}
/*
void func(struct test *tt,int length)
{
int i;
struct test *lt;
for(i = 0 ; i < length;i++)
{
lt = &tt[i];
printf("[%d]a:%d,b: %d\n",i,lt->a,lt->b);
}
/*printf("[0]a:%d,b: %d\n",lt->a,lt->b);
lt = &tt[1];
printf("[1]a:%d,b: %d\n",lt->a,lt->b);
lt = &tt[2];
printf("[2]a:%d,b: %d\n",lt->a,lt->b);*/
return;
}
*/
int main()
{
struct test lm[3] = {{1,2},{11,22},{111,222}};
struct test llm = {333,444};
func(lm);
func(&llm);
}