C++梁哥笔记day8 | 我的日常分享

C++梁哥笔记day8

类与对象

一、new运算符

C++中解决动态内存分配的方案是把创建一个对象所需要的操作都结合在一个称为new的运算符里。当用new创建一个对象时,它就在堆里为对象分配内存并调用构造函数完成初始化。

1
2
3
4
5
6
Person *person = new Person;  
相当于:
Person *person = (Person *)malloc(sizeof(Person));
if(person == NULL){
return 0;
}
  • new 给基本类型创建空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void test01(){
    //基本类型
    int *p = NULL;
    //p = (int *)malloc(sizeof(int));
    p = new int(100);//等价于 p = new int;*p = 100;
    cout<<"*p = "<<*p<<endl;
    //free(p);
    delete p;
    }

    运行结果:
    图片

  • new 给基本类型数组申请空间

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //创建字符数组
    char *pStr = new char[100];
    //创建整型数组
    int *pArr1 = new int[100];
    //创建字符数组并初始化
    char *pStr = new char[5]{"hello"};//错误
    char *pStr = new char[5]{'h','e','l','l','o'};//正确
    //创建整型数组并初始化
    int *pArr2 = new int[5]{1,2,3,4,5};

    //释放数组内存
    delete[] pStr;
    delete[] pArr1;
    delete[] pArr2;
1
2
3
4
5
6
7
8
9
10
void test02(){
int *arr = NULL;
//arr = (int *)malloc(sizeof(int)*5);
arr = new int[5]{0,1,2,3,4};
for(int i = 0; i < 5; i++){
cout<<arr[i]<<endl;
}
//数组空间的释放
delete [] arr;
}

运行结果:
图片

注意:
1、new没有加[] delete释放的时候就不加[]
2、new加[] delete释放的时候就加[]

  • new 从堆区实例化对象 (使用new创建一个类 )

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    class Person{
    private:
    char m_name[32];
    int m_num;
    public:
    Person(){
    cout<<"无参构造函数"<<endl;
    }

    Person(char *name,int num){
    strcpy(m_name,name);
    m_num = num;
    cout<<"有参构造函数"<<endl;
    }
    ~Person(){
    cout<<"析构函数"<<endl;
    }
    void showPerson(){
    cout<<"name:"<<m_name<<" m_num:"<<m_num<<endl;
    }
    };
    void test03(){
    Person *p1 = new Person;
    Person *p2 = new Person("lucy",100);
    // p2->showPerson();
    //delete 先调用析构函数 再释放空间
    delete p1;
    delete p2;
    }

    运行结果:
    图片

  • 对象数组
    本质是数组,元素是对象
    当创建一个对象数组的时候,必须对数组中的每一个对象调用构造函数,处理在栈上可以聚合初始化,必须提供一个默认的构造函数

1
2
3
4
5
void test04(){
//定义对象数组的时候 系统会自动给数组中的每个元素调用构造函数
//自动调用无参构造函数
Person arr1[5];
}

运行结果:
图片

如果想让对象数组中的元素调用有参构造 必须人为使用有参构造初始化

1
2
3
4
5
6
7
void test05(){
//初始化部分调用有参构造函数 未初始化部分调用默认构造函数
Person arr1[5]={Person("lucy",20),Person("bob",18)};
//arr1[0]就是第0个元素Person对象
arr1[0].showPerson();
arr1[1].showPerson();
}

运行结果:
图片

  • new创建对象数组
1
2
3
4
5
6
7
8
9
10
void test06(){
//第一种方式
Person *arr1 = new Person[5];//调用五个无参构造

//第二种方式
Person *arr2 = new Person[5]{Person("lucy",20),Person("bob",18)};//调用两个有参构造 和 三个无参构造函数

delete [] arr1;
delete [] arr2;
}

运行结果:
图片

  • delete void *可能会出错
    如果对一个void *指针执行delete操作,这将可能成为一个程序错误,除非指针指向的内容是非常简单的,因为它将不执行析构函数,以下代码未调用析构函数,导致可能内存减少
    1
    2
    3
    4
    5
    6
    void test07(){
    Person *p1 = new Person("lucy",100);
    p1->showPerson();
    void *p2 = p1;
    delete p2;
    }
    运行结果:
    图片
    没有调用析构函数

尽量不要用delete释放void *

为什么没有调用析构呢?
void *系统不知道所指向的类型,不知道去调用哪个对象的析构函数,

  • malloc、free和new、delete可以混搭使用吗?
    不可以。

二、静态成员变量详解

在类定义中,它的成员(包括成员变量和成员函数),这些成员可以用关键字static声明为静态的,成员静态成员。不管这个类创建了多少个对象,静态成员只有一个拷贝,这个拷贝被所有属于这个类的对象共享。

  • 静态成员变量
    在一个类中,若将一个成员变量声明为static,这种成员称为静态成员变量,与一般的数据成员不同的,无论建立多少个对象,都只有一个静态数据的拷贝。静态成员变量,属于某个类,所有对象共享。静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配了空间。
    静态成员变量必须在类中声明,类外定义。静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间。静态数据成员可以通过类名或者对象名来引用。
    总结:1、静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配了空间。2、静态成员变量必须在类中声明,类外定义。

成员包括:成员变量、成员方法(函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Data{
public:
int num;//普通成员变量
static int data;//静态成员变量(类中声明,类外定义)
};
//定义的时候不需要加static
int Data::data = 100;//类外定义,初始化
void test01(){
//data是公有静态成员变量 是属于类 没有定义对象 也可以通过类名称直接访问
cout<<"data="<<Data::data<<endl;
Data::data = 200;//赋值
cout<<"data="<<Data::data<<endl;

//data静态变量 也是属于所有对象的 是共享的 也可以通过对象名访问
Data ob1;
ob1.data = 300;
cout<<"data:"<<ob1.data<<endl;
}

运行结果:
图片

  • 静态成员函数的引出
    在类定义中,前面有static说明的成员函数称为静态成员函数。静态成员函数使用方式和静态变量一样,同样在对象没有创建前,即可通过类名调用。静态成员函数主要为了访问静态变量,但是不能访问普通成员变量。静态成员函数的意义,不在于信息共享、数据沟通,而在于管理静态数据成员,完成静态数据成员的封装。
    静态成员函数只能访问静态成员变量,不能访问普通成员变量,静态成员函数的使用和静态成员变量一样,静态成员函数也有访问权限,普通成员函数可访问静态成员变量、也可以访问非静态成员变量。但是普通成员函数是依赖对象的,必须有对象后才能使用,但是对于私有静态成员通常我们不想通过创建对象后再调用方法使用、如果类没有实例化对象,难道就不能使用data了吗,解决这些问题就要用到静态成员函数。