zoukankan      html  css  js  c++  java
  • C++面向对象_复制构造函数+构造函数+析构函数+static+友元

    person.h

    /**************************************
     在此处进行成员属性、函数声明

      自动生成4个
      1、无参构造函数   对private成员初始化
      2、析构函数        内存泄漏
      3、拷贝构造函数   深度赋值
      4、=运算符重载    深度赋值
    **************************************/

    #ifndef _person
    #define _person

    class Cat{
    public:
        void F();
    };

    class person{//抽象性
    private://封装性
        //const int id;  //const id=1;// error c++不允许直接赋值 只允许在构造函数中赋值
        int m_id;
        char* m_name;
    public:  
        static void PrintName(person * temp);
        //inline  成员函数默认都是内联函数 可以不加 inline
        void PrintName();
        //得到函数的地址
        void getAddress();
        int getM_id();
        /*
            运算符重载:
        */
        void operator=(person& temp){
            this->m_id=temp.m_id;
            //重新分配空间 深度赋值
            this->m_name=new char[10];
            strcpy(this->m_name, temp.m_name);
            cout<<"运算符重载"<<endl;
        }
    public:
        int GetId();
        /*
        explicit
        放在构造函数前面:
            表示在 实例化 赋值的时候不能隐形转化
            比如: person onePerson=1;
                   person onePerson(1);
            加了 explicit 就只会把 1 当成int
            不加  如果没有 构造函数只有一个参数是int的
            只有 一个参数是char * 型的 那么就会找该构造函数实例化
            此时就会把 1 隐形转化
            避免隐形转化在构造函数前加 explicit
        */
        
        /*
            拷贝构造函数
        */
        explicit person(person& temp){
            this->m_id=temp.m_id;
            //重新分配空间 深度赋值
            this->m_name=new char[10];
            strcpy(this->m_name, temp.m_name);
            cout<<"拷贝构造函数"<<endl;
        }

        /*
        构造函数
            1、没有返回值
            2、函数名和类名一样
            3、参数和传统函数一样
        */
        explicit person();
        explicit person(int id, char* name);
        explicit person(char* name);
        /*
        析构函数
            1、在对象销毁时调用
            2、作用,释放内存,等
        */
        ~person();

        /*
    ----------------
      友元:
    ----------------
    1、如果希望一个普通函数F中能够访问类C中的
    非公有成员,可以在类C中声明普通函数F为类C的友元
        class C{
            //注意这个函数是全局函数 没有定义C中
            friend void F();
        };

        void F(){
            //该函数可以访问类C非公有的成员
        }

    2、如果希望类C2的成员函数C2::F可以访问类C1的非公有成员
    可以在类C1中将类C2的成员函数C2 F声明为友元
        class C2{
            void F(){
                //该函数可以访问类C非公有的成员
            }
        };

        class C1{
            friend void C2::F();
        };

    3、如果希望类C2的【所有成员函数】可以访问类C1的非公有成员
    可以在类C1中将类C2的成员函数C2声明为友元
        class C2{
                //所有函数可以访问类C1非公有的成员
            void F(){
            
            }
        };

        class C1{
            //类C2可以访问类C1的非公有成员
            friend void C2;
        };
        */
        friend void test();
        friend void Cat::F();

    }; //注意此处的;  和c语言的struct{};  可以进行比较

    #endif _person

    person.cpp

    #include <string.h>
    #include <iostream>
    using namespace std;
    #include "person.h"

    /*
    在此处进行函数的实现
    */

    //静态函数  
    //调用方式: 类名::函数()
    /*
    声明:    static void PrintName(person temp);
    注意实现的时候就不需要加 static
    */  
    void person::PrintName(person * temp){
        cout<<"temp.m_name="<<temp->m_name<<endl;
    }
    //this指向当前实例  
    //用法: this->属性名
    void person::PrintName(){
        cout<<"this->m_name="<<this->m_name<<endl;
    }

    void person::getAddress(){
        cout<<"this="<<this<<endl;
    }

    int person::getM_id(){
        return this->m_id;
    }

    //:id(1)  初始化常量
    /*
        此种方法: 构造函数名():属性名1(值1), 属性名2(值2)...
        可以用于初始化常量,并且常量只能用此方法初始化
        也可以初始化成员变量
        此种方式不能初始化字符串
    */
    person::person()//:id(1)
    {
        this->m_id=122;
        /*
        注意事项:
            new 分配的内存 被所有person类型的 对象 所共享  
            只要有一个person类型的对象delete new分配的内存后
            其它person类型的对象也就不能访问该内存了
        */
        this->m_name = new char[10];
        strcpy(m_name, "tangtao");
    }

    person::person(int id, char* name)//:id(id) //可以通过参数初始化const
    {
        //this->id = 1;
        this->m_id = id;
        this->m_name = new char[10];
        strcpy(this->m_name, name);
    }

    person::person(char* name){
        this->m_name = new char[10];
        strcpy(this->m_name, name);
    }

    //释放内存 防止内存泄漏
    person::~person(){
        cout<<"delete............"<<endl;
        if(this->m_name!=NULL){
            delete this->m_name;
            this->m_name = NULL;
        }
    }

    int person::GetId()
    {
        return this->m_id;
    }

    void Cat::F(){
        person onePerson(12, "tangtao");
        cout<<"类2访问类1的非共有的成员=="<<onePerson.m_name<<endl;
    }

    Test.cpp

    #include <iostream>
    using namespace std;
    #include "person.h"
    #include <stdio.h>
    #include "person.h"
    /*
    类是对象的抽象
    对象是类的具体实现
    */
    /*class person{//抽象性
    private://封装性
        int m_id;
    public:
        char m_name[10];
        //静态函数  
        //调用方式: 类名::函数()   
        static void PrintName(person temp){
            cout<<"temp.m_name="<<temp.m_name<<endl;
        }
        //this指向当前实例  
        //用法: this->属性名
        void PrintName(){
            cout<<"this.m_name="<<this->m_name<<endl;
        }

    }; //注意此处的;  和c语言的struct{};  可以进行比较




    int main(){
        person onePerson={1, "tangtao"}; //什么是实例化 分配内存的过程,也就是对象
        //onePerson.m_id=12; //private
        strcpy(onePerson.m_name, "itao");
        //PrintName(onePerson);
        //onePerson.PrintName();
        person::PrintName(onePerson);
        onePerson.PrintName();
        cout<<onePerson.m_name<<endl;
        return 0;
    }
    */


    int test1(){
        //person onePerson; //无参的构造函数实例化对象
        //什么是实例化 分配内存的过程,也就是对象
        person onePerson(21, "itao");
        //实例化有参数的构造函数
        //onePerson.m_id=12; //private
        //strcpy(onePerson.m_name, "itao");
        //PrintName(onePerson);
        //onePerson.PrintName();
        //person::PrintName(&onePerson);
        //onePerson.PrintName();
        //cout<<"m_id="<<onePerson.getM_id()<<endl;
        //cout<<"person.size="<<sizeof(onePerson)<<endl;
        //cout<<onePerson.m_name<<endl;
        //onePerson.getAddress();
        //cout<<"temp="<<&onePerson<<endl;
        
        /*
        深度赋值:
            就是取成员的具体内容,
            而不是简单的指针赋值
        牵扯到两个概念:
            拷贝构造函数和运算符重载
        默认:
            浅赋值 就是指针赋值
        */
        //在初始化的同时赋值 才会执行拷贝构造函数
        person otherPerson = onePerson;
        
        //初始化后赋值 执行运算符重载
        person otherPerson2;
        otherPerson2=onePerson;
        //运算符重载与上相同
        //otherPerson.operator =(onePerson);
        
        /*
            特别注意:
        */
        person otherPerson3=person(12, "asd");
        //等价于 person otherPerson3(12, "asd");

        person otherPerson4;
        otherPerson4=person(12, "asd");
        
        /*
        自动生成拷贝构造函数
        */
        person otherPerson5="jack";
        //cout<<"otherPerson5="<<&otherPerson5<<endl;
        
        person otherPerson6;
        otherPerson6 = person("jack");



        //cout<<"地址"<<&onePerson<<endl;
        //cout<<"地址"<<&otherPerson4<<endl;
        return 0;
    }


    int test2(){
        /*
        const int:
            表示 是常量
        const int *:
            表示存放的是常量的地址,即指向常量
        const int * const
        或者
        int const * const
            表示指向常量的常量指针
        */
        const int i=1; //i不能被修改
        const int * pI1=&i; //不能通过pI1修改i
        const int * const pI2=&i; //不能通过pI2修改i 并且pI2也不能被修改
        //等价于==
        int const * const pI3=&i;

        /*
        函数后面加const
            void PrintName()const;
            void PrintName()const{
            
            }
        作用:
            在成员函数中用const锁定实例
            该函数内不能修改成员变量和常量
        */
        return 0;
    }

    //该函数为友元函数
    //友元函数中能访问类中非共有的成员
    void test(){
        person onePerson(11, "itao");
        cout<<"友元函数=="<<onePerson.m_name<<endl;    
    }

    int main(){
        //person onePerson(11, "itao");
        //cout<<onePerson.GetId()<<endl;
        //test();
        Cat oneCat;
        oneCat.F();

        return 0;
    }

  • 相关阅读:
    Spring 源码学习
    Feign Client 原理和使用
    算法基础:排序算法看这一篇就够了
    Spring 源码学习2
    Spring 源码学习
    最优包裹组合-贪心算法
    @Transactional 事务的底层原理
    Mysql索引扫盲总结
    snowflake原理解析
    分布式ID总结
  • 原文地址:https://www.cnblogs.com/qintangtao/p/2759755.html
Copyright © 2011-2022 走看看