<C++ - 构造和析构> 2018-01-10

 

 

/*
    回顾上节的内容:
            1.实现中的事情 物 ->类  
                    <属性 -> 成员变量>   
                    <行为 -> 成员函数>
            2.访问权限 public private (protected:受保护的)
                函数 公有  成员  私有  公有可以在类外访问  私有 只能类内访问
            3.struct 和class区别: 结构体就是公有的类
                                  类就是私有的结构体

         -->this 指针  指向对象本身 在成员函数中  可以在成员函数中访问成员变量或者是调用其他成员函数(在类外不能使用)


    新知识点:
        1.构造  析构函数
            1.1 构造函数
                成员变量  私有  只能用类里面的函数赋值 
                构造函数  定义一个对象的时候 同时给他初始化

                构造函数有时候也叫做: 构造器  函数名和类名相同  没有返回值  
                                        也不需要要调用(对象定义的时候自动调用 并且只调用一次)
                                        构造函数  可以重载  可以缺省(注意二义性)
                                        构造自己调用
                                        定义对象  对象后面没有()  -->无参构造
                                                 对象后面有()   调用有参构造
                                       
                                        定义对象的时候同时会调用构造函数
                                        不写构造函数的时候  定义对象的时候会不会调用构造函数  (会调用)
                                        没写  编译器会给一个默认构造(没有参数 没有执行任何功能)不做任何事情
                                        如果说你写了一个构造函数  编译器就不会给这个构造函数
             
             2.1析构函数  作用 析构 释放对象占用内存
                    没有返回值  没有参数  函数名就是类名前面加上一个  ~
                    析构  对象声命周期结束之后自动调用
                    如果没有写析构  编译器会分配一个默认析构(不做任何事情)

                    构造  释放 内存(构造中申请内存  析构中释放)
                       释放的是对象内部申请的内存
        2.new  delete
            2.1 new 和 delete会调用对象的构造和析构  malloc 和 free不会
            2.2 delete 如果是数组的话 那么加上[]  (不加就不会调用每个对象的析构函数)
        
            答疑课部分
        3.命令行参数
          指 main 的参数 int argc  char*argv[]    // _TCHAR*argv[] (多字节)
          argc 表示后面的指针数组的指针的个数  数组大小
          agrv 指向多个字符串(传入的参数)

          传递参数:
                1.拖动exe到cmd窗口  空格隔开  手动输入参数
                2.拖动文件到exe上

        argv[0] -->  一定是exe路径

        首先清楚 参数  -->根据参数写代码就可以了
*/
#include <iostream>
using namespace std;

//====================================类函数========================================
class sunmer
{
private:         // 私有成员不能在类外访问
    int x;       // 只是说明类中有哪些成员  不赋值
    double y;
public:
    // 无参数构造
    sunmer()   // 可以有参数  也可以没有参数  可以重载
    {
        cout << "调用的是无参构造函数" << endl;
        x = 0;
        y = 0; 
    }
    sunmer(int x, double y)     // 有参数构造
    {
        cout << "调用的是有参构造函数2" << endl;
        this->x = x;
        this->y = y;
    }
    sunmer(double y, int x = 0)   // 缺省的构造函数
    {
        cout << "调用的是缺省函数" << endl;
        this->x = x;
        this->y = y;
    }

    void play()
    {
        cout << "play well" << endl;
    }
    void setSummer()
    {
        //cin >> x >> y;
        cin >> this->x >> this->y;
    }
    void setSummer(sunmer&temp)   // 这个传递一个参数  (2)
    {
        temp.x = 2;
        this->x = 3;
    }
    void print()
    {
        cout << x << "\t" << y << endl;
    }
};
/**
    类 -->抽象
    成员赋值方式:
            1.构造函数    定义对象的时候给他赋值
            2.定义其他函数    后面用对象调用给他赋值
*/

class student
{
    int x;
public:
    student(int x)   // 有参数
    {
        cout << "调用构造函数" << endl;
        this->x = x;
    }
    /*student()
    {

    }*/
    ~student()     // 析构函数   1.可以重载不?  2.可以缺省不?   (没有参数 不能重载    缺省是给参数赋值默认值  没办法缺省)
    {
        cout << "调用析构函数" << endl;
    }
};

int main()
{
#if 0
    sunmer seven,six;       // 定义一个seven对象
    sunmer ou(3, 2.15);     // 调用有参数构造   参数可以是变量
    sunmer danny(2);        // 调用缺省构造函数

    ou.print();
    getchar();
    seven.setSummer(six);   // 调用(2)行的函数
    /**
        temp.x   ->相当等于: six.x
        thix->x  ->相对等于: seven.x
    */
    seven.play();            //函数调用的时候记得加括号
    seven.setSummer();        // 输入数据
    seven.print();            // 打印数据

#elif 0
    //student bug;   // 不写()   调用默认(无参)构造
    // 错误  不存在默认构造函数  解决方案1  自己写一个没有参数的构造函数
    // 解决方案2  调用有参构造函数  写参数

    //student arr[10];  // 定义类数组  对象没办法传递参数   -->调用无参构造
    // 用堆内存申请类的动态数组
    //student *p = new student(1);

#elif1
#endif   // 析构函数
    {
        // 生命周期
        student danny(1);
    }
    

    getchar();
    return 0;
}

/*
        作业:
            改写我们上次作业   用构造函数给他赋值(成员变量  换成私有属性)

*/

 

02、MySring(实例)

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

class myString    // 动态存放放字符串  用的是堆内存
{
private:
    char *str;   // 指针
    int size;    // 堆内存大小
    int lenth;   // 字符串长度
public:
    myString()   // 构造  1.没有放回值  2.什么时候调用
    {
        cout << "调用无参构造" << endl;
        str = NULL;
        size = 0;
        lenth = 0;
    }
    myString(char arr[])  // 传入字符串
    {
        lenth = strlen(arr);    // 先保留字符串的长度
        this->size = lenth + 1; // 多申请一点空间
        str = new char[this->size];  // 申请内存
        strcpy(str, arr);    // 拷贝字符串
    }
    ~myString()   // 析构函数: 1.没有返回值  2.没有参数  3.对象生命周期结束之后自动调用一次
    {
        cout << "调用析构函数" << endl;
        //delete[]str;    //  释放申请的内存  (这样会报错)
        if (str != NULL)
        {
            delete[]str;   // 释放申请的内存
            str = NULL;
            size = 0;
            lenth = 0;
        }
    }
};
int main()
{
#if 0   // 析构函数的例子
    myString danny("郑磊");
    // 释放str指向的这块内存  不是danny的这块内存
    
    danny.~myString();   // 析构可以手动调用

#endif
    /**
        new delete(会调用构造)  delete(会调用析构)
        malloc  free 直接申请/释放内存  不会调用构造析构
    */

    //myString *p = new myString[4];   //  申请内存
    //delete[]p;   // (释放内存)  如果不释放内存的话 内存泄漏
    //delete p;    // 如果有[] 会调用每个对象的析构函数
    /*
    myString *p = new myString;
    delete p;
    */


    myString *p = (myString*)malloc(sizeof(myString)* 4);
    // 这个没敢用
    free(p);
    getchar();
    return 0;
}

 

03、测试

// 2018-01-10-测试.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])  // 多字节  改多字节字符集
{
    printf("\n命令行参数\n");
    // 测试 代码 打印命令行参数
    for (int i = 0; i < argc; i++)
    {
        printf("%s\n", argv[i]);
    }
    getchar();
    return 0;
}

 

posted @ 2018-01-23 18:40  让优秀成为一种习惯  阅读(171)  评论(0编辑  收藏  举报