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

原文地址:https://www.cnblogs.com/qintangtao/p/2759755.html