文章目录
- Day4-4 New 与 delete 表达式(2025.03.20)
- 1. `new` 表达式的三个步骤
- 2. `delete` 表达式的两个步骤
- 3. `new[]` 与 `delete[]`
- Day5 类的定义和关键字再探(2025.03.24)
- 1. C++ 关键字 `const`、`static`、`extern`
- 2. 类的定义:Circle 和 Rect
- 3. 完整代码
- Day5-1 运算符重载(2025.03.24)
- 1. 复数类 `Complex` 及其运算符重载
- 2. 运算符重载的几种方式
- 3. 关键区别
- 4.完整代码
Day4-4 New 与 delete 表达式(2025.03.20)
在 C++ 中,new
和 delete
是用于动态内存管理的关键字。它们分别用于在堆上分配和释放对象或数组。
1. new
表达式的三个步骤
-
调用
operator new
标准库函数operator new
负责在堆上申请一块原始的、未初始化的内存空间,以便存储对象。- 如果申请失败,会抛出
std::bad_alloc
异常(除非使用nothrow
版本的new
)。
-
调用构造函数
- 在申请到的内存空间上调用构造函数,初始化对象的数据成员。
-
返回指针
- 返回指向新分配对象的指针,以供程序使用。
示例代码:
class A {
public:A() { cout << "A() constructor" << endl; }~A() { cout << "~A() destructor" << endl; }
};int main() {A* p = new A; // 调用 operator new 申请内存 -> 调用构造函数 -> 返回指针delete p; // 调用析构函数 -> 调用 operator delete 释放内存return 0;
}
2. delete
表达式的两个步骤
-
调用析构函数
- 在释放对象所占的内存前,先执行析构函数,以回收对象的数据成员所占用的资源(如动态分配的内存、文件句柄等)。
-
调用
operator delete
库函数- 释放对象本身所占用的内存空间,使其可被重新分配。
示例代码:
A* p = new A;
delete p; // 先调用析构函数,再释放内存
3. new[]
与 delete[]
new[]
用于动态分配对象数组,必须使用delete[]
释放。delete
只能释放单个对象,而delete[]
释放的是整个数组。
A* arr = new A[5]; // 申请 5 个对象的数组delete[] arr; // 释放数组
如果用 delete
释放 new[]
申请的数组,可能会导致未完全析构的对象泄漏。
Day5 类的定义和关键字再探(2025.03.24)
1. C++ 关键字 const
、static
、extern
const int global_a = 10; // 只读常量
static int s_b = 10; // 静态全局变量(仅限当前文件可见)
extern int SIZE = 10; // 外部变量(多个文件可共享)
const
:用于定义只读变量,防止意外修改。static
:修饰局部变量时,延长变量生命周期,修饰全局变量时,限制其作用域。extern
:用于声明外部变量,使其可以在多个文件中访问。
示例:
void test() {static int fun_c = 0; // 仅初始化一次,生命周期贯穿整个程序fun_c++;cout << "fun_c = " << fun_c << endl;
}
2. 类的定义:Circle 和 Rect
class Circle {
public:Circle(double r = 0) : _r(r) {cout << "Circle()" << endl;}~Circle() {cout << "~Circle()" << endl;}double getArea() const {return M_PI * _r * _r;}private:double _r;
};
要点:
- 构造函数(Constructor): 负责初始化对象,可以带默认参数。
- 析构函数(Destructor): 负责清理资源,名称前带
~
。 - 成员函数(Member Function):
const
关键字保证不会修改对象数据。
3. 完整代码
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>using namespace std;
//关键字
//const
const int global_a = 10;
//static
static int s_b = 10;
//extern
extern int SIZE = 10;
//三者的用途:const 修饰常量,static 修饰全局变量,extern 修饰外部变量void test()
{int local_v = 0;static int fun_c;//静态局部变量 可以延长变量的生命周期fun_c++;cout << "local_v = " << " " << local_v << " ," << "fun_c = " << " " << fun_c << endl;
}//定义一个圆
class Circle
{
public:Circle(double r = 0): _r(r){cout << "Circle(double r = 0)" << endl;}Circle(double r,char* name): _r(0), _name(new char[strlen(name) + 1]){strcpy_s(_name, strlen(name) + 1,name);cout << "Circle(double r = 0)" << endl;}~Circle(){cout << "~Circle()" << endl;}double getRadius() const{return _r;}//setRadiusvoid setRadius(double r){_r = r;}double getArea() const{return M_PI * _r * _r;}private:double _r;char* _name;
};//定义一个矩形
class Rect
{
public:Rect(double l = 0, double w = 0): _l(l), _w(w){cout << "Rect(double l = 0, double w = 0)" << endl;}~Rect(){cout << "~Rect()" << endl;}private:double _l;double _w;
};void testCircle()
{Circle c1(10);cout << "c1.getRadius() = " << c1.getRadius() << endl;cout << "c1.getArea() = " << c1.getArea() << endl;cout << endl << endl;Circle c2;c2.setRadius(20);cout << "c2.getRadius() = " << c2.getRadius() << endl;cout << "c2.getArea() = " << c2.getArea() << endl;
}int main()
{test();test();test();cout << endl << endl;testCircle();return 0;
}
Day5-1 运算符重载(2025.03.24)
1. 复数类 Complex
及其运算符重载
class Complex {friend Complex operator*(const Complex& lhs, const Complex& rhs);
public:Complex(double r = 0, double i = 0) : _real(r), _imag(i) {}Complex operator-(const Complex& rhs) const {return Complex(_real - rhs._real, _imag - rhs._imag);}Complex& operator++() { // 前置++++_real;++_imag;return *this;}Complex operator++(int) { // 后置++Complex tmp(*this);_real++;_imag++;return tmp;}Complex& operator+=(const Complex& rhs) {_real += rhs._real;_imag += rhs._imag;return *this;}void display() const {cout << _real << " + " << _imag << "i" << endl;}private:double _real;double _imag;
};
2. 运算符重载的几种方式
-
成员函数重载(适用于
+=
、++
、-
):Complex operator-(const Complex& rhs) const; Complex& operator++(); Complex operator++(int); Complex& operator+=(const Complex& rhs);
-
友元函数重载(适用于
+
、*
):friend Complex operator+(const Complex& lhs, const Complex& rhs); friend Complex operator*(const Complex& lhs, const Complex& rhs);
3. 关键区别
运算符 | 适用方式 | 说明 |
---|---|---|
+ | 普通函数 | 需要访问两个对象的数据,可用友元函数 |
- | 成员函数 | 只需要访问当前对象数据 |
++ | 成员函数 | 影响当前对象,前置++返回引用,后置++返回值 |
* | 友元函数 | 需要访问两个对象的数据 |
示例代码:
Complex c1(1, 2), c2(3, 4);
Complex c3 = c1 + c2;
c3.display();
总结:
- 友元函数适用于二元运算(如
+
、*
)。 - 成员函数适用于一元运算(如
++
)和复合赋值运算(如+=
)。
4.完整代码
#include <iostream>
#include <limits.h>using namespace std;//复数
class Complex
{friend Complex operator*(const Complex& lhs, const Complex& rhs);//Complex operator/(const Complex& rhs) const;
public:Complex(double r = 0, double i = 0): _real(r), _imag(i) {cout << "Complex(double r = 0, double i = 0)" << endl;}~Complex(){cout << "~Complex()" << endl;}double getReal() const{return _real;}double getImag() const{return _imag;}//运算符重载之成员函数Complex operator-(const Complex& rhs) const{return Complex(_real - rhs._real, _imag - rhs._imag);}//自增运算符重载Complex& operator++() //前置++{++_real;++_imag;return *this;}//后置自增运算符重载Complex operator++(int) //后置++{Complex tmp(*this);_real++;_imag++;return tmp;//返回类型是一个临时对象,所以不适用引用类型}//前置++和后置++的区别?//解答:前置++返回是对象的引用,是左值可以取地址//后置++返回的是局部对象,是右值不能取地址//+=运算符重载//复合赋值运算符重载,推荐以成员函数的形式重载Complex& operator+=(const Complex& rhs){_real += rhs._real;_imag += rhs._imag;return *this;}void display() const{if (_imag > 0){cout << _real << " + " << _imag << "i" << endl;}else if (_imag == 0){cout << _real << endl;}else{cout << _real << " - " << -_imag << "i" << endl;}}
private:double _real;double _imag;
}; //“operator + ”必须至少有一个类类型的形参
//int operator+(int lhs, int rhs)
//{
// //return _real + rhs;
//}//运算符重载之普通函数
Complex operator+(const Complex& lhs, const Complex& rhs)
{return Complex(lhs.getReal() + rhs.getReal(), lhs.getImag() + rhs.getImag());
}//运算符重载之友元函数(推荐使用)
Complex operator*(const Complex& lhs, const Complex& rhs)
{return Complex(lhs._real * rhs._real - lhs._imag * rhs._real,lhs._real * rhs._real + lhs._real * rhs._real);
}void test()
{Complex c1(1, 2);cout << "c1 = ";c1.display();cout << endl << endl;Complex c2(3, 4);cout << "c2 = "; c2.display();cout << endl << endl;Complex c3 = c1 + c2;cout << "c3 = c1 + c2 = ";c3.display();
}void test2()
{Complex c1(1, 2);cout << "c1 = ";c1.display();cout << endl << endl;Complex c2(3, 4);cout << "c2 = "; c2.display();cout << endl << endl;Complex c3 = c1 - c2;cout << "c3 = c1 - c2 = ";c3.display();}void test3()
{Complex c1(1, 2);cout << "c1 = ";c1.display();cout << endl << endl;Complex c2(3, 4);cout << "c2 = ";c2.display();cout << endl << endl;Complex c3 = c1 * c2;cout << "c3 = c1 * c2 = ";c3.display();c3 += c1;cout << "c3 += c1 = ";c3.display();}void test4()
{Complex c3(4, 6);cout << "c3 = ";c3.display();cout << endl << endl;++c3;cout << "++c3 = ";c3.display();cout << endl << endl;c3++;cout << "c3++ = ";c3.display();Complex c4(4, 6);cout << "c4 = ";c4.display();c4++;cout << "c4++ = ";c4.display();cout << "前置++返回是对象的引用,是左值可以取地址,后置++返回的是局部对象,是右值不能取地址";
}int main(int argc, char* argv[])
{//test();//test2();//test3();test4();return 0;
}