<C++ - 拷贝构造> 2018-01-12

 01、拷贝构造:

#include <iostream>
using namespace std;
/*
    回顾上节的内容:
        1.构造和析构
        2.new  delete
        3.delete[]

    新的知识 (拷贝的关键字: memcpy)

        1.拷贝构造 ->构造函数  函数名和类名相同  没有返回值
            定义: 用拷贝的方式构造对象  调用拷贝构造
                参数为 该类对象的构造函数

        关于引用:
            1.拷贝构造  参数必须为引用
            2.加引用的好处 节约内存 效率比指针高
        构造和析构  调用时候  对象出生和死亡
        引用直接用别名方式 (没有出生新的对象)





    拷贝如果是直接赋值(指针 申请了堆内存的话 两个对象的指针指向同一块堆内存)释放一个对象的内存 另外一个对象 指针就无效了


    **深拷贝     每个对象单独申请内存(一个一口锅)-->看拷贝中有没有单独申请内存
    浅拷贝    直接赋值(两个人共同背锅)

    注意    :    拷贝构造:  
                    问题1:        引用
                    问题2:        深拷贝



*/
//========================================类函数======================================
class A
{
private:
    char *arr;   // 指针  它申请一块堆内存
    int x;       // x内存大小 x个char
public:
    A()        // 参构造函数    没有返回值  自动调用
    {
        cout << "调用无参构造函数" << endl;
        this->arr = NULL;    // 给对象中的arr赋值
        this->x = 0;
    }    
    A(int x)
    {
        cout << "调用有参构造函数" << endl;
        this->arr = new char[x];    // 申请内存
        this->x = x;
    }
    A(A & other)  // 拷贝构造       
    {
        /**
        参数是同类型的对象   other形参 -->相当是 sum   
        shis指向当前对象相当于 (23)的fnu   
        other拷贝的是sum --> 调用拷贝构造函数  所以必须加引用

        拷贝 -->内容拷贝  直接用参数  定义一个新的形参
        引用  取别名 不全定义新的形参
        */
        cout << "拷贝构造函数" << endl;
        this->arr = new char[other.x];
        memcpy(this->arr, other.arr, other.x);   // 内存拷贝函数  //头文件: memcry.h
        this->x = other.x;
    }
    ~A()    // 析构函数  --> 没有返回值  没有参数  自动调用
    {
        cout << "调用析构函数" << endl;
        if (arr != NULL)
        {
            delete[]arr;   // 释放内存
            arr = NULL;
        }
    }

    // 判断两个人能否结婚
    void married(A other1, A other2)  // married 通过对象调用  那个对象调用 this指向哪个对象
    {
        // 通过对象调用  -> this指针指向的对象
        this->x;
        other1.x;
        other2.x;
    }
    void mamied(A other)
    {
        cout << "是否婚配" << endl;
    }
};
/**
    new  delete  申请对象的内存空间的时候 调用对象的构造/析构函数
    delete[]  调用每个对象的析构函数
*/

//==========================================新内容====================================


int main()
{
#if 0
    {
        A sum;                // 定义一个对象sum   在栈区 (调用无参构造)
        A fnu(sum);            // 调用拷贝构造   (23)
        /**
            sum.arr 指向一个内存空间
            fnu.arr = sum.arr  fnu.arr和sum.arr指向同一块内存空间


            看拷贝之后的结果  拷贝之后两个指针指向同一块内存  浅拷贝
                                指向不同的空间  深拷贝
        */
        sum.mamied(fnu);    // 函数 传参  实参 -->形参赋值  形参拷贝实参
    }

#endif
    A danny, logs, st;
    danny.married(logs, st);
    
    getchar();
    return 0;
}

02、static和const:

 

#include <iostream>
using namespace std;
/*
    static  静态
        1.修饰普通变量  内存在静态存储区(内存四区  堆区 栈区 全局静态常量区 代码区) 只会开辟一次内存  函数结束不释放内存
        2.修饰全局变量  限制作用域 -> 变量只能在当前文件使用(对针extern)
                extern :在这个文件中使用其他文件中的变量
        3.修饰类的成员变量(C++)
            3.1 静态成员变量  不能在构造函数中赋值  必须在类外赋值 -> 用类名访问
            3.2 静态成员不专属于某个对象   属于这个类  所有对象公用同一个静态成员
            静态成员函数  不能修改非静态成员(没有this指针)

    const    修饰常量  const int   只能定义的时候赋值  定义之后不能修改值
              修饰指针  const int*: 常量指针  /  int *const: 指针常量
              const int*p   *p 不可以改  --> 指向的内容不可以改 
              int *const p   p 不能改  --> 不能改指针的指向




              const A&temp 和 A&const temp
              修饰 &temp  -> 不能改引用的内容
              修饰的temp  引用 不能变成其他对象的引用(本身也不能变成其他对象的引用  所以加或者不加  没区别)



              1.const 修饰成员变量  常属性成员变量  常量 -> 赋值之后不能修改

              2.初始化形参列表  格式
                const 成员变量 只能通过初始化成员 列表赋值
                后面也不能修改它的值


    3.其他const用法:
        3.1. 修饰参数 不能修改参数的值
             一般对象 传参使用引用 为了避免在参数中修改了这个实参的值  加上const
        
         const 修改形参  限定形参的使用  不限定实参

        3.2. 修饰返回值  放函数前面(不用)

        3.3 修饰成员函数  常属性成员函数  放在函数后面
            常属性成员函数 :1.不能修改成员变量的值   2.不能调用非常属性成员函数


*/
class people
{
private:
    int age;
    char name[30];
    static int earth;    // 静态成员
public:
    /* 构造函数和析构函数没有返回值 */
    people()
    {
        cout << "调用无参构造函数" << endl;
        age = 0;
        strcpy(name, "baby");   // 拷贝
        //earth = 0;
    }
    void eat()
    {
        this->age;
        this->earth++;
    }
    void print()
    {
        cout << earth << endl;
    }
    static void play()    // 静态成员函数  --> 不能使用this指针
    {
        //age++;
        //this->age++;
        earth++;
    }
};
int people::earth = 100;
int fun()
{
    static int x = 1;
    x++;
    return x;
}
class human
{
private:
    const int x;
    int y;
public:
    /*human()   // 无参构造
    {
        //x = 0;   // 构造中不能直接给这个常属性成员赋值
        y = 0;
    }*/
    // 初始化成员列表
    // 格式: 构造函数名(参数):成员名1(参数1),成员名2(参数2)....// 用括号里面的参数给成员赋值
    human() :x(0), y(0)
    {
        cout << "调用无参构造" << endl;
        y = 3;    // 赋值顺序  先成员列表  后函数体
    }
    human(int x, int y) :x(x)
    {
        cout << "调用有参构造" << endl;
        this->y = y;
    }
    void print() const
    {
        cout << x << '\t' << y << endl;
    }
    void married(const human&other)   // 没有限定实参
    {
        //other.y = 100;  // 错误修改了实参的值
        print();
    }
    void play() const   // 常属性成员函数 :1.不能修改成员变量的值   2.不能调用非常属性成员函数
    {
        
    }
};
int main()
{
#if 0
    /*
    cout << fun() << endl;
    cout << fun() << endl;
    cout << fun() << endl;
    */
    people memore;  // 定义一个对象
    memore.eat();
    memore.eat();
    memore.print();
    memore.eat();
    memore.print();
    memore.play();

#endif
    human bug;
    human fum(3, 5);
    bug.print();
    fum.print();

    bug.married(fum);
    fum.print();

    getchar();
    return 0;
}
/* 
    strcpy(拷贝函数)   --> const

    作业:
        1. 写一个 mystring类(用指针申请堆内存  存放一个字符串)
                需要写拷贝构造

        2. 给类中const成员和static成员初始化

*/

 

posted @ 2018-01-24 19:02  让优秀成为一种习惯  阅读(146)  评论(0编辑  收藏  举报