C++:02.类的构造函数、析构函数、拷贝函数

知识点:

面试题:finalize , finally, final 之间的区别

finalize : java中垃圾回收回收该对象的时候会调用的方法 (c 中的析构函数)

finally: finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常,即使try语句块中有return

final : 在java中,final可以用来修饰类,方法和变量(成员变量或局部变量)。

修饰类:当用final修饰类的时,表明该类不能被其他类所继承。
修饰方法:当用final修饰方法时,把方法锁定,以防止继承类对其进行更改不能被重写。(注意:若父类中final方法的访问权限为private,
        将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。)
修饰变量:final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。类似于C++中的const。

1. 构造函数(可以有很多)

1.1.定义

class Student{
public:
    // 构造函数
    Student(){// 空参构造函数
        cout << "空参构造函数" << endl;
    }

    /*Student(char* name):age(0){//  一个参数构造函数,相当于 this->age = 0;
        cout << "一个参数构造函数" << endl;
        // this->name = name;
        // this->age = age;
    }*/

    Student(char* name):Student(name,0){ // 调用两个参数的构造函数,注意:先会调用两个参数的构造函数,然后才会执行当前构造函数
        cout << "一个参数构造函数" << endl;
    }

    Student(char* name,int age){ // 两个参数构造函数
        cout << "两个参数构造函数" << endl;
        this->name = (char*)malloc(sizeof(char)*100);
        strcpy(this->name,name);
        // this->name = name; // 这样赋值不行
        this->age = age;
    }

    // 2. 析构函数,如果有在对象内部开辟堆内存,可以在析构函数中释放内存
    ~Student(){
        cout << "析构函数" << endl;
        // 临终遗言:对象被回收的时候会被调用
        // 释放内存
        free(this->name);
        this->name = NULL;
    }

    // 4. 拷贝构造函数,对象会有一个默认的拷贝构造函数,用来对象之间赋值
    Student(const Student& stu){ // 常量的引用
        cout << "拷贝构造函数" << endl;
        // this->name = stu.name;// 浅拷贝
        // 如果动态开辟内存,一定要采用深拷贝
        this->name = (char*)malloc(sizeof(char)*100);
        strcpy(this->name,stu.name);
        this->age = stu.age;
    }

private:
    int age;
    char* name;

public:
    int getAge(){
        return this->age;
    }

    char* getName(){
        return this->name;
    }

    void setAge(int age){
        this->age = age;
    }

    void setName(char* name){
        this->name = name;
    }

};

1.2.调用

    // 1. 默认调用空参的构造函数
    Student stu;
    stu.setAge(24);
    stu.setName("Eastrise");

    // 2. 调用两参构造函数
    Student stu("Eastrise",24);

    // 3.用 new 关键字,返回的是一个 Student 的一级指针
    Student* stu = new Student("eastrise",25);

    // 4.用 malloc 的方式,并没有调用空参的构造函数
    Student* stu = (Student*)malloc(sizeof(Student));
    stu->setAge(25);
    stu->setName("eastrise");

    // 构造函数相互调用
    Student* stu = new Student("eastrise"); // 会先调用两参的再调用一参的

2. 析构函数(只能有一个)

析构函数:如果有在对象内部开辟堆内存,可以在析构函数中释放内存

如果是 new 的对象,则必须调用 delete 才会调用到析构函数

    // 2. 析构函数,如果有在对象内部开辟堆内存,可以在析构函数中释放内存
    ~Student(){
        cout << "析构函数" << endl;
        // 临终遗言:对象被回收的时候会被调用
        // 释放内存
        free(this->name);
        this->name = NULL;
    }


int main(){
    Student* stu = new Student("eastrise");

    cout << stu->getName() << ", " << stu->getAge() << endl;

    delete(stu);
}

3.malloc、free、new、delete 区别

  1. malloc/free 他们是一套, new/delete 它们是一套
  2. malloc/free 不会去调用构造函数和析构函数
  3. new/delete 会调用构造函数和析构函数

4. 拷贝构造函数和调用场景

struct Person{
    int age;
    char* name;
};

int main(){
    Person person1 = {25,"east"};

    Person person2 = person1;// = 是赋值,把里面所有定义的属性赋值,c/c++ 编译器帮我们做的

    cout << &person1 << " , " << &person2 << endl; // 地址不一样,是深拷贝

    person1.name = "sss";

    cout << person2.name << " , " << person2.age << endl;

}

总结:非指针运算的 = 应该都是深拷贝

	// 4.拷贝构造函数,对象会有一个默认的拷贝构造函数,用来对象之间的赋值
	Student(const Student& stu){// 常量的引用
		cout << "拷贝构造函数" << endl;
		// this->name = stu.name;// 浅拷贝
		// 如果动态开辟内存,一定要采用深拷贝
		this->name = (char*)malloc(sizeof(char)* 100);
		strcpy(this->name, stu.name);
		this->age = stu.age;
	}

在这里插入图片描述

  1. = 会调用拷贝构造函数

        Student stu1("Darren", 24);
        Student stu2 = stu1; // = 是赋值,把里面所有定义的属性赋值,c/c++ 编译器帮我们做的,其实会调用对象的拷贝构造
    
        // 以下方式不会调用拷贝构造函数
        Student stu2;// 声明变量,开辟变量内存
        stu2 = stu1; // 这个不会去调用拷贝构造函数,但是会赋值 c 的类似
    
  2. 第二种场景 作为参数返回的时候会调用拷贝构造函数

    Student getStudent(char* name){
        Student stu(name);// 栈 ,方法执行完,这个对象会被回收,但是发现调用了拷贝构造函数
        cout << &stu << endl;
        return stu;// 会返回一个新的 Student 对象,而栈内开辟的 stu 是会被回收 
    }
    
    Student stu = getStudent("Jack");
    cout << &stu << endl;
    
  3. 第三种场景 作为参数传递的时候会调用拷贝构造函数

    void printStudent(Student stu){// stu 是该方法栈中一个新的对象,拷贝构造函数赋值,方法执行完会调用析构函数
        cout << stu.getName() << " , " << stu.getAge() << endl;
    }
    
    Student stu("Darren", 24);
    printStudent(stu);
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值