C++11QT复习(二)
文章目录
- 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;
}
//setRadius
void 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;
}