友元
1.1 什么是友元?
1.2 三类友元
友元函数:
class student
friend void checkId(student&);
友元函数可以放在共有区域,也能够放在私有区域
一个函数可以是多个类的友元函数,只需要在各个类中分别声明
友元函数的调用和普通函数一样
/*===============================================
* 文件名称:friend_function.cpp
* 创 建 者:
* 创建日期:2023年05月30日
* 描 述:
================================================*/
#include <iostream>
#include <string>
using namespace std;
class student{
public:
student(string n,string i):name(n),ID(i){}
void doTest();
void getExamResult();
public://类student的友元函数
// friend bool checkId(student& );//检测学生属性
// friend void setScore(student&,int score);//设置学生成绩
private://属性定义
friend bool checkId(student& );//检测学生属性
friend void setScore(student&,int score);//设置学生成绩
string name;
string ID;
int score;
};
bool checkId(student& s)
{
cout << "检查考生" << s.name << "身份信息" << endl;
return true;
}
void setScore(student& s,int score)
{
s.score = score;
}
void student::doTest()
{
cout << name << "开始考试" << endl;
}
void student::getExamResult()
{
cout << name << "的成绩是" << score << endl;
cout << "考试结果是" << (score >= 90?"合格":"不合格") << endl;
}
int main()
{
student xiaoming("xiaoming","12138");
checkId(xiaoming);
xiaoming.doTest();
setScore(xiaoming,95);
xiaoming.getExamResult();
return 0;
}
友元类:
friend class demo;
可以申明一个类为另一个类的友元类
友元关系是不能继承
友元关系是单向的,如果A是B的友元,但B不一定是A的友元,要看有没有友元的申明
友元关系不具有传递性,如果B是A的友元,而C是B的友元,那C不一定是A的友元,要看C是否被定义为A的友元。
/*===============================================
* 文件名称:friend_class.cpp
* 创 建 者:
* 创建日期:2023年05月30日
* 描 述:
================================================*/
#include <iostream>
#include <string>
using namespace std;
class student;
class Examiner{
public:
bool checkId(student& );//检测学生属性
void setScore(student&,int score);//设置学生成绩
};
class student{
public:
student(string n,string i):name(n),ID(i){}
void doTest();
void getExamResult();
public:
friend Examiner;//友元类的声明
private://属性定义
string name;
string ID;
int score;
};
bool Examiner::checkId(student& s)
{
cout << "检查考生" << s.name << "身份信息" << endl;
return true;
}
void Examiner::setScore(student& s,int score)
{
s.score = score;
}
void student::doTest()
{
cout << name << "开始考试" << endl;
}
void student::getExamResult()
{
cout << name << "的成绩是" << score << endl;
cout << "考试结果是" << (score >= 90?"合格":"不合格") << endl;
}
int main()
{
Examiner ex;
student xiaoming("xiaoming","12138");
ex.checkId(xiaoming);
xiaoming.doTest();
ex.setScore(xiaoming,95);
xiaoming.getExamResult();
return 0;
}
友元成员函数:
可以将A的成员函数设置为B的友元,这个函数就成为了B的友元函数
/*===============================================
* 文件名称:friend_menber.cpp
* 创 建 者:
* 创建日期:2023年05月30日
* 描 述:
================================================*/
#include <iostream>
#include <string>
using namespace std;
class student;
class Examiner{
public:
bool checkId(student& );//检测学生属性
void setScore(student&,int score);//设置学生成绩
};
class student{
public:
student(string n,string i):name(n),ID(i){}
void doTest();
void getExamResult();
public:
friend bool Examiner::checkId(student&);//友元类函数的声明,本质不是学生类的成员函数,所以没有this指针
friend void Examiner::setScore(student&,int score);
private://属性定义
string name;
string ID;
int score;
};
bool Examiner::checkId(student& s)
{
cout << "检查考生" << s.name << "身份信息" << endl;
return true;
}
void Examiner::setScore(student& s,int score)
{
s.score = score;
}
void student::doTest()
{
cout << name << "开始考试" << endl;
}
void student::getExamResult()
{
cout << name << "的成绩是" << score << endl;
cout << "考试结果是" << (score >= 90?"合格":"不合格") << endl;
}
int main()
{
Examiner ex;
student xiaoming("xiaoming","12138");
ex.checkId(xiaoming);
xiaoming.doTest();
ex.setScore(xiaoming,95);
xiaoming.getExamResult();
return 0;
}
hqyj
拷贝构造函数,浅拷贝,深拷贝
2.1 拷贝构造函数的定义:用一个已经存在的类的对象去初始化一个新的类的对象
当用户自己没有定义自己的拷贝构造函数的时候,系统会给我们生成一个缺省的拷贝构造函数(字节拷贝,把存在对象的数据拷贝到新的对象里面去,称之为浅拷贝)
demo(demo& d)
{
aa=d.aa;
bb=d.bb;
}
2.2 什么情况下调用拷贝构造函数
1 使用一个存在的对象去初始化一个新的对象
demo d1(100,200);
demo d2(d1);//方式一
demo d3=d1;//方式二
2 类对象作为一个函数的输入参数
void func1(demo & d);
3 从函数里面返回一个类对象
demo return_demo()
{
demo d1;
return d1;
}
2.3 缺省拷贝构造(浅拷贝)
当用户自己没有定义自己的拷贝构造函数的时候,系统会提供缺省的拷贝构造函数,它会一个字节一个字节的进行拷贝,这种行为称为“浅拷贝”
2.4 自定义拷贝构造(深拷贝)
针对类需要从堆空间动态申请内存的情况,用户要定义自己的拷贝构造函数,申请相同的内存,然后复制相应的数据,避免二次内存释放,导致系统崩溃
/*===============================================
* 文件名称:copy_constructor.cpp
* 创 建 者:
* 创建日期:2023年05月30日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
class Demo
{
public:
Demo(int a,int b):aa(a),bb(b){}
//拷贝构造函数:复制构造函数
///
Demo(Demo& d)
{
cout << "demo copy constructor function" << endl;
aa = d.aa;
bb = d.bb;
}
///
void show()
{
cout << "a = "<< aa << " b = " << bb << endl;
}
private:
int aa;
int bb;
};
void debug()
{
cout << "********************" << endl;
}
void func1(Demo d)
{
d.show();
}
Demo returnDemo()
{
Demo d(101,202);
return d;
}
int main()
{
debug();
Demo d1(100,200);
d1.show();
debug();
Demo d11(1000,2000);
///
//拷贝构造 使用一个已经存在的对象去初始化一个新的对象
Demo d2(d1);//d1作为参数传递进来
d2.show();
debug();
/
Demo d3 = d1;//用d1去创建d3
d3.show();
debug();
d3 = d11;//只是赋值,不能初始化调用demo构造函数
d3.show();
debug();
//当使用类对象作为函数的参数
func1(d3);
debug();
/
d3 = returnDemo();
d3.show();
debug();
return 0;
}
运算符重载
1.1运算符重载的概念
返回的数据类型:operator <运算符符号> (参数表)
Demo operator += (Demo &d1, Demo& d2);
1.2友元运算符重载
friend <返回的数据类型> operator <运算符符号>(参数表)
friend Demo operator += (Demo &d1, Demo& d2);
因为友元操作符没有this指针,对于一目操作符,需要1个参数,对于二目操作符,需要两个参数。
/*===============================================
* 文件名称:friend_operator.cpp
* 创 建 者:
* 创建日期:2023年05月30日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
class integer//类是用户自己定义的数据类型
{
public:
integer(int ii):i(ii){}
void show()
{
cout << "i = " << i << endl;
}
/没有this指针所以需要两个对象///
friend integer operator + (integer& a,integer& b);
friend integer operator ++ (integer& a);//++a;
friend integer operator ++ (integer& a,int b);//a++;int b 不起作用只是为了区别前++ 后++
friend integer operator += (integer& a,integer& b);
private:
int i;
};
integer operator ++ (integer& a)//++a;
{
integer tmp(++a.i);
return tmp;
}
integer operator ++ (integer& a,int b)//a++;
{
integer tmp(a.i++);
return tmp;
}
integer operator + (integer& a,integer& b)
{
integer tmp(a.i + b.i);//返回的就是integer
return tmp;
}
integer operator += (integer& a,integer& b)
{
integer tmp(a.i += b.i);
return tmp;
}
void debug()
{
cout << "---------------" << endl;
}
int main()
{/*
string s1 = "hello";
string s2 = "world";
string s3 = "dasdasddasdasda";
s3 = s1 + s2; //对加号进行重载
cout << "s1=" << s1 << endl;
cout << "s2=" << s2 << endl;
cout << "s3=" << s3 << endl;
*/
debug();
integer i1(100);
i1.show();
debug();
integer i2(200);
integer i3(0);
i3 = i1 + i2;//对加号进行重载
i3.show();
debug();
(++i3).show();
(i3++).show();
i3.show();
debug();
i3 += i2;
i3.show();
debug();
return 0;
}
1.3 成员函数运算符重载
<返回的数据类型> operator <运算符符号>(参数表)
Demo operator += ( Demo& d2);
因为成员函数有this指针,对于一目操作符,不需要参数,对于二目操作符,需要一个参数。
/*===============================================
* 文件名称:friend_operator.cpp
* 创 建 者:
* 创建日期:2023年05月31日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
class demo
{
public:
demo(int size):len(size)
{
p = new int[len];
// p = new int(10);只是分配了1个内存空间,用10去初始化它
//assert(NULL != p);
}
void show();
~demo()
{
delete []p;
p = NULL;
}
//对于下标的操作符只能在成员函数中做
int& operator [](int index);//访问[]内的元素
private:
int *p;
int len;
// int index;
};
int& demo::operator [](int index)
{
if(p != NULL)
{
return this->p[index];
}
else
{
cout << "p is NULL" << endl;
static int aa;
return aa;
}
}
void demo::show()
{
for(int j=0;j<100;j++)
{
cout << p[j] << " " ;
}
cout << endl;
}
int main()
{
demo a1(100);
for(int i=0;i<100;i++)
{
a1[i] = i + 1;
}
a1.show();
cout << a1[3] << endl;;
return 0;
}
/*===============================================
* 文件名称:member_operator.cpp
* 创 建 者:
* 创建日期:2023年05月31日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
class Point
{
public:
Point():x(0),y(0){}
Point(double x1,double y1):x(x1),y(y1){}//构造函数重载
void show()
{
cout << "x=" << x << " y=" << y << endl;
}
Point operator + (Point& p);
Point operator ++(); //++p
Point operator ++(int b);//p++
Point operator * ();
Point operator * (Point& p);
// Point operator += (Point& p);
Point operator +=(Point& p);
private:
double x;
double y;
};
Point Point::operator + (Point& p)//第一个Point是函数返回值,第二个是类下成员函数的引用
{
Point tmp(this->x+p.x,this->y+p.y);
return tmp;
}
Point Point::operator ++() //++p
{
++(this->x);
++(this->y);
return *this;
}
Point Point::operator ++(int b)//p++
{
Point tmp(*this);
x++;//不能写成tmp.x++,因为程序运行完之后x会++
y++;
return tmp;
}
Point Point::operator * ()
{
Point tmp(this->x * this->x,this->y * this->y);
return tmp;
}
Point Point::operator * (Point& p)
{
Point tmp(this->x * p.x,this->y * p.y);
return tmp;
}
Point Point::operator +=(Point& p)
{
this->x += p.x;
this->y += p.y;
return *this;
}
void debug()
{
cout << "--------------" << endl;
}
void test()
{
Point p(3.12,4.32);
Point q(5.76,6.89);
Point r = p + q;
r.show();
debug();
(++r).show();
(r++).show();
r.show();
debug();
(*r).show();
debug();
Point s = p * q;
s.show();
debug();
s += p;
s.show();
}
int main()
{
debug();
test();
debug();
return 0;
}
1.4总结
除去极个别的运算符,大多数运算符能够重载
只能够对现有的运算符进行重载,不能创建新的运算符
操作符重载的实质是函数重载,必须遵循函数重载的原则(不能够仅仅通过返回值类型不同进行重载)
操作符重载只能使用在用户自定义的数据类型(class,struct)
模板
将数据类型参数化,用同一套代码去处理不同数据类型和应用场景
2.1 模板函数
template <class T>
//将T看作特定的数据类型int
T add(T a,T b)
{
return a+b;
}
/*===============================================
* 文件名称:add_func_template.cpp
* 创 建 者:
* 创建日期:2023年05月31日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
//template <class T> 以前的写法
class integer
{
public:
integer():aa(0){}
integer(int a):aa(a){}
void show()
{
cout << "aa=" << aa << endl;
}
integer operator + (integer& b)
{
integer tmp;
tmp.aa = this->aa + b.aa;
return tmp;
}
private:
int aa;
};
template <typename T>//template不能与定义的分开
T add(T a,T b)
{
return a + b;
}
int main()
{
cout << add(10,20) << endl;
cout << add(1.121,2.3454) << endl;
string s1 = "hello ";
string s2 = "world";//要先定义字符串,不能直接放进add里加🏠
cout << add(s1,s2) << endl;
integer i1(100);
integer i2(200);
add(i1,i2).show();
return 0;
}
/*===============================================
* 文件名称:swap_func_template.cpp
* 创 建 者:
* 创建日期:2023年05月31日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
template<typename T>
void Swap(T& a,T& b)
{
T tmp = a;
a = b;
b = tmp;
}
class Point
{
public:
Point():x(0),y(0){}
Point(double xx,double yy):x(xx),y(yy){}
void show()
{
cout << "x=" << x << " y=" << y << endl;
}
private:
double x;
double y;
};
int main()
{
int a1 = 100,a2 = 200;
cout << "a1=" << a1 << " " << "a2=" << a2 << endl;
Swap(a1,a2);
cout << "a1=" << a1 << " " << "a2=" << a2 << endl;
double a3 = 3.1414,a4 = 3.1313;
cout << "a3=" << a3 << " " << "a4=" << a4 << endl;
Swap(a3,a4);
cout << "a3=" << a3 << " " << "a4=" << a4 << endl;
string s1 = "xiaoming";
string s2 = "limei";
cout << "s1=" << s1 << " " << "s2=" << s2 << endl;
Swap(s1,s2);
cout << "s1=" << s1 << " " << "s2=" << s2 << endl;
Point p1(1.1,2.2);
Point p2(3.3,4.4);
Swap(p1,p2);
p1.show();
p2.show();
return 0;
}
//
2.2,模板类
template<typename T>
class container
{
private:
T data;
};
/*===============================================
* 文件名称:demo_template_class.cpp
* 创 建 者:
* 创建日期:2023年05月31日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
template <typename T>
class demo//不同数据类型的容器
{
public:
demo(T a):data(a){}
T get();
void show()
{
cout << "data=" << data << endl;
}
private:
T data;
};
template <typename T>//使用模板
T demo<T>::get()//demo类与T的数据类型要绑定关系
{
return data;
}
int main()
{
//对T进行实例化
demo<int> intdemo(100);
intdemo.show();
demo<double> doubledemo(12.2121);
doubledemo.show();
demo<string> stringdemo("asdas");
stringdemo.show();
return 0;
}
/*===============================================
* 文件名称:stack_template_class.cpp
* 创 建 者:
* 创建日期:2023年05月31日
* 描 述:
================================================*/
#include <iostream>
using namespace std;
///存不同类型的数据//
template<typename T>
class Stack
{
public:
Stack(int a):len(a),p(NULL),index(-1)
{
p = new T[len];
}
~Stack()
{
delete [] p;
p = NULL;
}
void push(T a);
T pop();
void show();
private:
T *p;
int len;
int index;
};
template<typename T>
void Stack<T>::push(T a)
{
if( index < len-1 )//还能往里面塞数据时是top=98
{
p[++index] = a;
}
}
template<typename T>
T Stack<T>::pop()
{
if(index >= 0)
{
return p[index--];
}
else
exit(1);
}
template<typename T>
void Stack<T>::show()
{
for(int i=0;i<=index;i++)
{
cout << p[i] << " ";
}
cout << endl;
}
int main()
{
Stack<int> intstack(100);
for(int i=0;i<100;i++)
{
intstack.push(i+1);
}
intstack.show();
for(int j=0;j<50;j++)
{
intstack.pop();
}
intstack.show();
///
Stack<string> strstack(100);
for(int i=0;i<100;i++)
{
string s1 = "string";
strstack.push(s1 + to_string(i+1));
}
strstack.show();
for(int j=0;j<50;j++)
{
strstack.pop();
}
strstack.show();
return 0;
}