C语言和C++学习笔记

C和C++基础

// new/delete 是一套 会调用构造函数 与 析构函数 【C++标准规范】

// malloc/free是一套 不调用构造函数 与 析构函数 【C的范畴,虽然不推荐,但是也是可以的】
释放内存之后,
free()
arr= null 置空指针

在这里插入图片描述

动态空间开辟的是堆,静态空间是栈空间
在这里插入图片描述

   // TODO ========================== 下面代码对我们上节课 遗留点 完成  末尾工作了
    if (new_arr) { // new_arr != NULL 进去if, 重新开辟的堆空间是成功的
        free(new_arr);
        new_arr = NULL;
        arr = NULL; // 他还在指向那块空间,为了不出现悬空指针,指向NULL的空间
    } else { // 重新开辟的堆空间是失败的
        free(arr);
        arr = NULL;
    }
    
// C/C++编译器 数组作为参数传递,会把数组优化成指针(为了高效率)
void getLen(int * resultLen, int intarr[]) { // 模仿了 strLen函数
// TODO  拷贝构造函数的注意点:
// Student stu1("李鬼", 34);

// Student stu2;
// stu2 = stu1; // 这样赋值是不会调用 自定义拷贝构造函数,但是会调用默认赋值
// Student stu2 = stu1;  // 这样赋值是会调用 自定义拷贝构造函数,我们自己赋值

C++静态

//已经编译不成功,不 允许这样初始化
static int id = 9;


    // 先声明
    static int id;
    // 再实现
    int Dog::id = 9;
  • 静态的总结:
  • 1.可以直接通过类名::静态成员(字段/函数)
  • 2.静态的属性必须要初始化,然后再实现(规则)
  • 3.静态的函数只能取操作静态的属性和方法(Java)

3、C++对象中,为什么需要this

// main函数弹栈会 隐士代码:(栈区:delete student …, 堆区需要自己手动delete)

class Student {
private:
    char *name;
    int age;

public:
    static int id; // 先声明

在这里插入图片描述

1、分为多个区域,生成代码时会进入栈区,代码会进入代码区域
2、静态类型id,会进入静态区,当任意一个student修改时,全部的id值都会修改
3、public: // 默认的构造函数 栈区开辟空间 暴露 地址 == this指针 (和Java一致的思路)

4、const 修饰函数的this意义何在

class Worker {
public:
    char * name;
    int age = NULL; // C++中不像Java,Java有默认值, 如果你不给默认值,那么就是系统值 -64664

    // int * const  指针常量 指针常量【地址对应的值能改,地址不可以修改】
    // const int *  常量指针 常量指针【地址可以修改,地址对应的值不能改】
    // 纠结:原理:为什么可以修改age
    // 默认持有隐士的this【类型 * const this】
    // 类型 * const 指针常量:代表指针地址不能被修改,但是指针地址的值是可以修改的
  void change1() {
        // 代表指针地址不能被修改
        // this = 0x6546;  // 编译不通过,地址不能被修改,因为是指针常量
        // 地址不可以修改
        // this = 0x43563;

        // 隐士的this
        // 但是指针地址的值是可以修改的
        // 地址对应的值能改
        this->age = 100;
        this->name = "JJJ";
    }
    
        // 默认现在:this 等价于 const Student * const  //常量指针常量(地址不能改,地址对应的值不能改)
           // 原理:修改隐士代码  const 类型 * const 常量指针常量
    void changeAction() const {
        // 地址不能改
        // this = 0x43563;

        // 地址对应的值不能改
        // this->age = 100;
    }

在这里插入图片描述

友元函数

    // 定义友元函数 (声明,没有实现)
    friend void updateAge(Person * person, int age);

重载


class Derry {
private:
    int x,y;

    // 系统是这样写的  常量引用:不允许修改,只读模式
    // const 关键字的解释
    // & 性能的提高,如果没有&  运行+ 构建新的副本,会浪费性能
    // 如果增加了& 引用是给这块内存空间取一个别名而已,还是同一个地址
    Derry operator + (const Derry& derry1) {
        // this指针 指向当前对象,所以只需要一个
        int x = this->x + derry1.x; // 我在类的里面,是可以拿私有成员的
        int y = this->y + derry1.y; // 我在类的里面,是可以拿私有成员的
        return Derry(x, y);
    }

    // 运算符- 重载
    Derry operator - (const Derry & derry1) {
        int x = this->x - derry1.x;
        int y = this->y - derry1.y;
        return Derry(x, y);
    }

    // 对象++ 运算符 重载
    void operator ++() { //  ++对象
        this->x = this->x + 1;
        this->y = this->y + 1;
    }
    void operator ++ (int) { // 对象++
        this->x = this->x + 1;
        this->y = this->y + 1;
    }

    // istream 输入 系统的
    // ostream 输出 系统的
    // 输出 运算符重载 复杂 涉及到规则  重载<<
    friend void operator << (ostream & _START, Derry derry1) {
        // 输出换行:<< endl;
        _START << " 单 哥开始输出了 " << derry1.x << " ! " << derry1.y << " 哥结束了 " << endl;
    }

    // 多个的  ostream 输出 系统的
    // 输出 运算符重载 复杂 涉及到规则  重载 >>
    /*friend ostream & operator >> (ostream & _START, const Derry & derry1) {
        _START << " 多 哥开始输出了 " << derry1.x << " ! " << derry1.y << " 哥结束了 " << endl;
        return _START;

        // RxJava 链式调用  .操作符.操作符.操作符 你每次都是放回this  一个思路
    }*/

    // istream 输入 系统的
    friend istream & operator >> (istream & _START, Derry & derry) {
        // 接收用户的输入,把输入的信息,给x

        // _START >> derry.x;
        // _START >> derry.y;

        // 可读性不好,简化了
        _START >> derry.x >> derry.y;

        return _START;
    }
};

深拷贝和浅拷原理

浅拷贝
class Student
{
public:

	int age;
	char * name;

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

	Student(char * name) :Student(name, 99) {
		cout << "一个参数构造函数 this:" << (int)this << endl;
	}

	Student(char * name, int age) {
		cout << "二个参数构造函数 this:" << (int)this << endl;

		this->name = (char *)malloc(sizeof(char *)* 10);
		strcpy(this->name, name);

		this->age = age;
	}

	~Student() {
		cout << "析构函数执行 &this->name:" << (int)this->name << endl;

		free(this->name);
		this->name = NULL;
	}

	// 默认有一个拷贝构造函数 隐士的 我们看不见
	// 一旦复写了拷贝构造函数,默认的还在吗? Java的构造函数一个思路
	// 自定义拷贝构造函数 如果有堆成员,必须采用深拷贝
	Student(const Student & stu) {
		// stu 旧地址

		// this 新地址

		// s2 = 新地址

		cout << "拷贝构造函数 &stu:" << (int)&stu << " this:" << (int)this << endl;

		// 【浅拷贝】:新地址name  旧地址name 指向同一个空间,会造成,重复free的问题,引发奔溃
		// 新地址name = 旧地址 (浅拷贝)
		// this->name = stu.name;

		// 【深拷贝】
		this->name = (char *)malloc(sizeof(char *)* 10);
		strcpy(this->name, name);

		this->age = stu.age;

		cout << "拷贝构造函数2 this->name:" << ((int) this->name) << "  stu.name:" << (int)stu.name << endl;

		// 深拷贝 后面见  原理全部打通的时候讲
	} // 此拷贝构造函数执行完 旧会出现一个 this==新地址  给 main函数的 stu


	// 默认的拷贝构造函数 是浅拷贝
};

void showStudent(Student stu) {
	cout << "showStudent函数:" << (int)&stu << "  " << stu.name << "," << stu.age << endl;
}

void main() {
	Student stu("刘奋", 31);

	cout << "main函数:" << (int)&stu << "  " << stu.name << "," << stu.age << endl;

	showStudent(stu); // 弹栈后 新地址name释放一遍
	// showStudent(stu); // 弹栈后 新地址name释放一遍
	// 两次释放新地址name 会奔溃

	// 释放一次新地址name  再释放一次旧name也报错
    //浅拷贝多次执行会报错,有
	showStudent(stu);

    showStudent(stu);


	showStudent(stu);


//	showStudent(stu);

	getchar();
} // main函数弹栈 stu 旧地址


// 专业技能:1.研究过C++语言深拷贝原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dNwnPFKX-1690813594915)(https://note.youdao.com/yws/res/3344/WEBRESOURCE70978b000481820b5014a2e91403619b)]

1、浅拷贝,每次拷贝会生成新的地址,但新旧地址都指向同一个内存空间,所以释放时如果重复执行就会报错
2、深拷贝:每次都会开辟新的内存空间

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值