跳转至

构造函数和析构函数

构造函数(相当于创建)、析构函数(相当于销毁)

创造对象的时候,数据初始化,根据需要分配内存,进行初始化操作。

对象不再需要的时候,C++自动调用析构函数,进行清理操作,释放内存。

构造函数 名称和类的名称是一样的 后面一个`()`。

析构函数 前面加一个~

class X
{
    int i;
public:
    X();//构造函数 函数名和类名一样。
    ~X();//析构函数
};

X::X()
{
    cout << "这是构造函数" << endl;
}

X::~X()
{
    cout << "这是析构函数" << endl;
}
void test()
{
    {
        X x;//创建对象 自动调用构造函数
    }//作用域。 测试析构函数。自动销毁。C++自动调用析构函数
}

构造函数可以有参数。构造函数根据需要做成有参数或没参数。析构函数永远没有参数。

class Tree
{
    int height;
public:
    Tree(int initialHeight);//带参数的构造函数
    ~Tree();
    void grow(int years);
    void printsize();
};

Tree::Tree(int initialHeight)
{
    height = initialHeight;
}

Tree::~Tree()
{
    cout << "inside Tree destructor" << endl;
    printsize();
}

void Tree::grow(int years)
{
    //成长了多少年
    height += years;
}

void Tree::printsize()
{
    cout << "Tree height is " << height << endl;
}
void test()
{
    {
        Tree t(12);
        t.printsize();

        t.grow(4);
        t.printsize();
    } //作用域。结束之后调用析构函数
}

例二:

// C++的Stash  虽然是C++写的 但还是C语言的写法。没有构造函数和析构函数
struct Stash
{
    int size;// 每一个是多大。存字符串的话就是最多的存多少字符。
    int quantity;// 数量。一共可以保存多少个。
    int next;// 已经保存了多少个。
    unsigned char* storage;// 指针


    // 一些操作  C++可以放到里面
    // 函数是在结构里面的,所以函数定义的时候要写 结构名加::
    // 这些函数也叫 这个结构的成员
    void initialize(int size);  //这是C语言的创建和清理,不是C++的构造和析构函数
    void cleanup();
    void* fetch(int index);
    int add(const void* element);
    int count();
    // 扩大内存
    void inflate(int increase);
};

这种写法不太好,使用对象的时候,需要单独写初始化,如果忘了写就麻烦。

清理也是,需要手动去写。

C++有构造和析构,则不需要,自动的。

优化:

Stash:

// C++的Stash  虽然是C++写的 但还是C语言的写法。没有构造函数和析构函数
struct Stash
{
    int size;// 每一个是多大。存字符串的话就是最多的存多少字符。
    int quantity;// 数量。一共可以保存多少个。
    int next;// 已经保存了多少个。
    unsigned char* storage;// 指针


//    void initialize(int size);  //这是C语言的创建和清理,不是C++的构造和析构函数
//    void cleanup();

    //构造和析构函数
    Stash(int size);
    ~Stash();

    void* fetch(int index);
    int add(const void* element);
    int count();
    // 扩大内存
    void inflate(int increase);
};

Stack栈

class Stack
{
    class Link //堆栈中的每一个数据都是Link。
    {
        void* data;//Link中的数据
        Link* next;//指针 指向下一个数据
        Link(void* dat, Link* nxt);//构造函数
        ~Link();//析构函数
    }* head;//头
public:
    Stack();
    ~Stack();
//    void initialize();//堆栈初始化
    void push(void* dat);//把数据压入堆栈
    void* pop();//从堆栈中拿数据,只能从一头拿 不能从中间拿。把head指向的数据拿出来,head指向下一个。
    void* peak();//只看一下数据,不拿出来。
//    void cleanup();
};

集合的初始化

一个类是一个集合,类里面有很多数据成员,类是很多数据成员的集合。

集合就是很多的数据在一起。

最简单的集合就是数组。

数组初始化了就有数据,没有初始化里面就是垃圾数据。

//数组的初始化
int a[5] = {1,2,3,4,5};
//    int b[6];//没有初始化,里面就是垃圾数据
int b[6] ={0};//默认的给个0
cout << b[2] << endl;
int c[] = {1,2,3,4};//可以不指定数组的大小,C++自动的计算
/**
sizeof c 数组的大小
sizeof *c 第一个数的大小
*/
for (int i = 0; i < sizeof c / sizeof *c; i++) {
  cout << c[i] << endl;
}

数组使用大括号初始化,

结构sturct也可以用大括号初始化。

struct X
{
    int i;
    float f;
    char c;
};

//初始化
X x1 = {1,2.2,'c'};

class使用大括号初始化,必须是public。

struct默认是public。

只有没有构造函数,没有私有成员,才可以使用大括号形式初始化。

如果类class有构造函数或者有私有成员,必须调用构造函数去初始化。不能使用大括号形式。

class X
{
public://类使用大括号初始化 必须是public
    int i;
    float f;
    char c;
};

//初始化
X x1 = {1,2.2,'c'};
//数组
X x2[3] = {{1,1.1,'a'},{2,2.2,'b'}};
class Z
{
    int i,j;
public:
    Z(int ii, int jj)
    {
        i = ii;
        j = jj;
    }
    void print()
    {
        cout << "i = " << i << ", j = " << j << endl;
    }
};
//调用
void test()
{

    Z zz[] = {Z(1,2),Z(3,4),Z(5,6),Z(7,8)};
    for (int i = 0; i < sizeof zz / sizeof *zz; i++) {
        zz[i].print();
    }
}

默认构造函数

C++类没有写构造函数,C++编译的时候会自动加上一个没有参数的构造函数。并且这个构造函数里什么都不做。也没有初始化,使用的话,里面就是垃圾数据。 一般自己写上一个构造函数。

构造函数可以写多个。参数不一样。

创建对象的两种方法

  1. 在栈里面创建对象
  2. 在堆里面创建对象

在堆里要用指针。内置的类型也一样。

int h = 99;//在栈里
Stack s1;//对象在栈里
int* p = new int;//在堆里
//在堆里 用指针
Stack* s2 = new Stack;//在堆里创建的对象必须使用指针。没有参数的构造函数 后面可以不写小括号。

string str1("hello");//在栈里
string* str2 = new string("hello");//在堆里

cout << str1 << "," << *str2 << endl;

堆更灵活。用多少创建多少。

栈 事先知道用多少 运行执行之后不能改变

堆比栈稍慢。

new就是在堆里。

没有参数的构造函数 后面可以不写小括号。