C++ 友元、拷贝构造函数,深拷贝,浅拷贝、运算符重载、函数模板、类模板 5.31

友元

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独memories

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值