Advertisement

C++知识点(持续更新...)

阅读量:

目录

C++基础

输入输出

bool类型

new操作符

new和malloc的区别

malloc分配内存失败的情况:

引用

函数参数默认值

函数重载

函数重载碰到函数默认参数

类和对象

封装

类的构成--三种权限

类和结构体的区别



C++基础

输入输出

复制代码
 #include<iostream>

    
 //cin cout 从内存中输入输出 分别是 istream类型 ostream类型
    
 //c++的头文件库包含c语言的头文件库 可以写scanf和printf
    
 using namespace std;
    
 //namespace命名空间 std-标准
    
 //使用标准命名空间 限制cin/cout的使用范围在std下
    
 namespace S
    
 {
    
 	int a;
    
 }
    
 int a, b;//全局
    
 int main()
    
 {
    
     //cin 从控制台读入内容到变量。 cout从变量输出内容到控制台。
    
 	cin >>a >> b;
    
 	cout << a <<" " << b<<endl;//endl--换行
    
 	S::a = 4;//S是作用域
    
 	cout << a << " " << b << endl;
    
 	cout << S::a << " " << b << endl;
    
 	return 0;
    
 }
    
  
    
  
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/Vdf8yGv4NhIJelMPtpcobCF2nOAY.png)

bool类型

  • bool类型 :是c++中一种整型类型 只占1字节 值仅有两个 false(0)和true(1)
  • 非零的正负数都是1(false)

为什么只占一个字节?

答:1字节等于8位长的数据单位,大多数的计算机用1个字节表示1个字符、数字或其他字符,故1字节足够表示两个值了

复制代码
 #include<iostream>

    
 using namespace std;
    
  
    
 int main()
    
 {
    
 	bool a1 = -1 ;    //将被转换为true,非零正负值都转换为true。
    
 	bool a2 = 0;      //将被转换为false
    
 	int b1 = true;    //将被转换为1
    
 	int b2 = false;   //将被转换为0
    
 	
    
    cout << a1 << endl;
    
 	cout << a2 << endl;
    
 	cout << b1 << endl;
    
 	cout << b2 << endl;
    
 return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/E3SM1RGXyWlzifDuhmsVcICgrHPL.png)

new操作符

  • 是C++中在堆区开辟数据的
  • 语法:new+数据类型
  • 利用new创建的数据会返回数据对应类型的指针
  • 在堆区申请内存,释放时用delete 释放数组是用delete[]
  • new申请数组时返回首元素的地址,申请int型变量返回的是这块地址
复制代码
 int main()

    
 {
    
 	int* a1 = new int;//在堆区申请一块内存为int类型的内存 随机值
    
 	cout << a1 << endl;
    
 	delete a1;
    
  
    
 	int* a2 = new int();//在堆区申请一块内存为int类型的内存 值为0
    
 	cout << a2 << endl;
    
 	delete a2;
    
  
    
 	int* a3 = new int(4);//在堆区申请一块内存为int类型的内存 4
    
 	cout << a3 << endl;
    
 	delete a3;
    
  
    
 	int* a4 = new int [3];
    
 	for (int i = 0; i <3; i++) 
    
     cout << a4[i]<<" ";//在堆区申请一块内存为int类型的数组 值随机值
    
 	delete[]a4;//释放时不加[]会发生 内存泄漏(这块内存丢了,找不到)
    
  
    
 	int* a5 = new int[3] {1, 2, 3};//在堆区申请int类型数组 值为1 2 3
    
 	cout << a5;
    
 	delete[]a5;
    
     cout<<a5;//报错,释放的空间无法找到并访问
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/bO0sXLPiFla6Ctydc3ZxIefj7UQ1.png)
new和malloc的区别

new是在堆区申请内存的,如果给类或者结构体申请内存的话会优先调用malloc 再调用构造函数,
释放new申请的内存需要使用delete,释放数组需要delete[],delete会先调用析构函数在调用free,
当这个类的析构函数没有作用时,也可以使用free释放new申请的堆区空间

  • 1.返回值 new返回值不需要强转 malloc返回值需要强转‘
  • 2.名字:new是运算符可以重载 malloc是c语言库函数不可以重载
  • 3.参数:new不需要传入具体字节个数 malloc需要
  • 4.函数体:new先调用malloc再调用构造函数给成员变量赋值 delete先调用析构在调用free,malloc只分配堆区内存
  • 5.申请内存失败:new会抛出异常 malloc返回空
malloc分配内存失败的情况:

(1) 参数不正确

复制代码
>     int*p =(int *)malloc(-12);//不能为负数
>  
>     cpp
>  
>     

(2) 堆区没足够的空间

引用

1.性质

  • 作用是给变量起别名,引用必须初始化,且初始化不能为空,引用不能改变引用关系(底层是指针常量type *const pointer)),指针常量不可修改
  • 引用可以作为函数的参数和函数返回值存在,但是引用不能接收局部变量 加static可接收
  • 引用不占内存,函数传参时,利用引用的技术让实参和形参代表的是同一块内存空间
  • 引用分为:左值引用,右值引用,万能引用(在左值引用前加const)。左值引用只能接收左值,右值引用只能接收右值,万能引用都能接收
  • 左值是有名字有地址的变量,右值是无名字无地址的变量。匿名对象(只存在当前行,下一行就被释放)和常量都是右值

** 【注】 const修饰形参,防止形参改变实参**

【问】在C++中引用不能返回局部变量的的原因有:

  1. 局部变量的生命周期在函数返回后结束。
  2. 但是引用的生命周期会延续到调用的上下文环境中。
  3. 这样就出现了一个引用指向的内存已经被释放的非法引用。使用这个无效的引用可能会导致程序崩溃或其他难以预料的后果。

2.参数传递有两种方式

  • 值传递
复制代码
 void test01(int a, int b)//值传递不修改原参数的值

    
 {
    
 	int c = a;
    
 	a = b;
    
 	b = c;
    
 }
    
    
    
    
    cpp
    
    
  • 引用传递
复制代码
 void test02(int &a, int &b)

    
 {
    
 	int c = a;
    
 	a = b;
    
 	b = c;
    
 }
    
    
    
    

左值引用右值引用

复制代码
 #include<iostream>

    
 using namespace std;
    
 //返回局部变量引用
    
 int& test01() {
    
 	int a = 10; //局部变量
    
 	return a;
    
 }
    
  
    
 //返回静态变量引用
    
 int& test02() {
    
 	static int a = 20;
    
 	return a;
    
 }
    
  
    
 int main() {
    
  
    
 	//不能返回局部变量的引用
    
 	int& ref = test01();
    
 	cout << "ref = " << ref << endl;
    
 	cout << "ref = " << ref << endl;
    
  
    
 	/*有名字的变量是左值例如:a = 1 ,a为左值,例如: 2 ,2 是右值
    
 	左值引用只能接收左值,右值引用只能接收右值*/
    
 	int&& R = 2;//右值引用接收右值
    
 	int a = 2;
    
 	int& R1 = a; //左值引用只能接收左值
    
  
    
 	//int &&R2 = a; //报错
    
 	//int &R3 = 2; //报错
    
  
    
 	//万能引用:前面用const 修饰
    
 	const int& R4 = 2;
    
 	const int&& R5 = 3;
    
  
    
 	//如果函数做左值,那么必须返回引用
    
 	int& ref2 = test02();
    
 	cout << "ref2 = " << ref2 << endl;
    
 	cout << "ref2 = " << ref2 << endl;
    
  
    
 	test02() = 1000;
    
  
    
 	cout << "ref2 = " << ref2 << endl;
    
 	cout << "ref2 = " << ref2 << endl;
    
  
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/hSiPsl5bo7Nfn89wuX4D3LOrTkaG.png)

3.匿名对象(右值)

  • 没有名字的对象
  • 只存在于当前行,到下一行就被释放掉了
  • 函数以引用方式返回的值是左值 不引用返回的是匿名对象

4.引用和指针

  • 都可以修改目标对象的值
  • 都可以用于传递函数参数
  • 引用必须在生命时初始化,指针可以随时初始化

函数参数默认值

c++中参数的形参列表中的形参是可以有默认值的

必须是从右向左依次赋默认值

函数在主函数下面定义需要声明 声明时给默认值,实现时不需要给了

复制代码
 //void fun(int a = 1, int b = 2, int c = 3)

    
 //{
    
 //	cout << a << b << c << endl;;
    
 //}
    
  
    
 //函数在主函数下面定义需要声明 声明时给默认值,实现时不需要给
    
 void fun(int a = 1, int b = 2, int c = 3);
    
  
    
 int main()
    
 {
    
 	fun(1);
    
 	fun(1, 22);
    
 	fun(1, 22, 333);
    
 	return 0;
    
 }
    
  
    
 void fun(int a, int b, int c)
    
 {
    
 	cout << a << b << c << endl;;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/em5HpMQ2Y1krIUET4OlStZs9wXNi.png)
函数重载

1.定义

在同一个作用域下,函数名字相同,参数类型 或 个数 或 顺序不同

【注】:函数的返回值不作为函数重载的条件

复制代码
 void fun() { cout << "无参" << endl; }

    
 void fun(int a) { cout << "int" << endl; }
    
 void fun(int a, double b) { cout << "int double" << endl; }
    
 void fun(double a, int b) { cout << "double int" << endl; }
    
  
    
 int main()
    
 {
    
 	fun();
    
 	fun(2, 1.0);
    
 	fun(5);
    
 	fun(1.8, 2);
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/km3GHqOSozMEnulWpYLyajbt5TPc.png)

2.c语言为什么不能重载而c++可以?

C语言和c++的编译方式不同,c++中编译器编译后函数名是由原函数名+参数类型构成 ,参数不同就是函数名不同,调用时不会发生冲突

而C语言编译方式起完的名字还是自己 不能重载会发生冲突

3.函数重载的调用时期

函数在调用时 是在编译期间确定调用哪个重载函数的 ,根据实参类型确定的。编译器会选择一个最合适的函数来执行

4.extern "C" 声明全局变量函数

函数重载碰到函数默认参数

在一个类中,当无参数的构造函数和带默认参数的构造函数重载时,有可能产生二义性

复制代码
 //1.引用作为传递条件

    
  
    
 void func(int& a)
    
 {
    
 	cout << "func(int a)调用" << endl;
    
 }
    
 void func(const int& a)
    
 {
    
 	cout << "func(const int &a)调用" << endl;
    
 }
    
  
    
 //2.函数重载碰到函数默认参数
    
  
    
 void func2(int a, int b = 10)
    
 {
    
 	cout << "fun2(int a,int b=10)调用" << endl;
    
 }
    
  
    
 void fun2(int a)
    
 {
    
 	cout << "fun2(int a)调用" << endl;
    
 }
    
 int main()
    
 {
    
 	int a;
    
 	func(a);//调用无const
    
 	func(10);//调用有const
    
  
    
 	func2(10);
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/fiPHL3EpSzlOjyWa8X5VJxMtn6Uu.png)

类和对象

1.面向对象三大特征 封装 继承 多态

c++-->万物皆对象 对象:凡是占有内存的 int a a是对象

2.属性是成员变量 行为是成员函数或者成员方法

3.在定义对象时,若定义的是指向此对象的指针变量,则访问此对象的成员时,不能用“.”操作符,而应该使用“->“操作符。如

封装

意义:

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制

【注】类内声明 类外实现时要加作用域

空类大小是1

设计一个类求圆的周长

复制代码
 class Circle

    
 {
    
 public:
    
 	double r;
    
 	void area()
    
 	{
    
 		cout << 2 * 3.14 * r;
    
 	}
    
 };
    
 int main()
    
 {
    
 	Circle c;
    
 	c.r = 5.8;
    
 	c.area();
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/SIhAUl7EDgWtcf3VMQdxamqsY94r.png)

设计一个类显示学生信息

复制代码
 #include<string>

    
 class Student
    
 {
    
 public:
    
 	string name;
    
 	int sid;
    
 	void set_name(string n)
    
 	{
    
 		name = n;
    
 	}
    
 	//类内声明 
    
 	void card();
    
 };
    
 //类外实现 要加作用域
    
 void Student::card()
    
 {
    
 	cout << "姓名:" << name << " " << "学号:" << sid;
    
 }
    
 int main()
    
 {
    
 	Student s1;
    
 	s1.set_name("张三");
    
 	s1.sid = 202305;
    
 	s1.card();
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/0Cu2UHD5E9AkldgKnM4oR7jBOTbx.png)

类的构成--三种权限

public 公有权限 类内 子类 对象可以访问

protected 受保护权限 类内和子类能访问

private 私有权限 只有类内能访

【注】数据设置为私有 为了保证数据的准确性,提高安全性

复制代码
 #include<iostream>

    
 using namespace std;
    
 #include<string>
    
  
    
 class Person
    
 {
    
 public://公有权限  类内 子类 对象可以访问
    
 	string name;
    
 	//name = "123";//没有申请空间不能访问
    
 protected://受保护权限 类内和子类能访问
    
 	string car;
    
 private://私有权限 类内能访问
    
 	string password;
    
 public:
    
  
    
 	void set_car(string c)
    
 	{
    
 		car = c;
    
 	}
    
 	void set_password(string s)
    
 	{
    
 		password = s;
    
 	}
    
 	void printf()
    
 	{
    
 		cout << name << car << password;
    
 	}
    
 	void fun()
    
 	{
    
 		name = "张三";
    
 		car = "红旗";
    
 		password = "123654";
    
 	}
    
 };
    
 int main()
    
 {
    
 	//创建对象时申请内存  给成员变量分配内存
    
 	Person p;
    
 	p.name = "李四";
    
 	p.fun();
    
 	p.set_car("劳斯莱斯");
    
 	p.set_password("666");
    
 	p.printf();
    
 	//p.car = "拖拉机";//受保护权限不能调用
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/iVLqbvmyprZOYJNSRTfjc6ls4xUE.png)
类和结构体的区别

【问】c++中类和结构体的唯一区别?

默认的访问权限和继承权限不同,类的默认访问权限是私有的结构体是公有的

复制代码
 #include<iostream>

    
 using namespace std;
    
 #include <iomanip>
    
 #include<cmath>
    
 class C1//数据设置为私有  为了保证数据的准确性,提高安全
    
 {
    
 	int m_A;//默认是私有权限
    
 };
    
 struct C2
    
 {
    
 	int m_a;//默认是公共权限
    
 };
    
 int mian()
    
 {
    
 	C1 c1;
    
 	c1.m_A = 10;//错误,访问权限是私有的
    
  
    
 	C2 c2;
    
 	c2.m_A = 10;//正确,访问权限是公共
    
  
    
 	system("pause");
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/lSsvjt9LDUfVTniRgbO3mXxYoecK.png)

对象的初始化和清理

构造函数和析构函数
构造函数

语法:类名+(){}

编译器提供的默认构造函数是空实现

构造函数可以是私有的

1.当写一个类时 c++的编译器会提供4个默认函数 : 构造函数 析构函数 浅拷贝 赋值运算符

2.构造函数是一种特殊的成员函数

  • 主要作用是在创建对象时用来给成员变量赋值 ,名字必须与类名相同 ,可以有任意类型的参数可以重载,但是不能有返回值
  • 在创建对象的时候编译器自动调用构造函数 且只调用一次 ,如果没有实现构造函数编译器会提供默认构造函数

一个类的指针对象,如果分配空间的话,就会调用构造函数,在析构时要手动调用delete 如果没有分配就,不会调用。

复制代码
 #include<iostream>

    
 using namespace std;
    
 #include<string>
    
 #include<iomanip>
    
  
    
 class Pointer
    
 {
    
 	int* p;
    
 	int a, b;
    
 public:
    
 	Pointer()//构造函数没有返回值 //如果没有实现构造函数,编译器会提供一个默认的构造函数
    
 	{
    
 		//赋值:给已存在的变量一个值
    
 		//初始化:再创建一个变量时给他一个值
    
 		b = a;
    
 		a = 1;
    
 		cout << "无参构造" << a << b;;
    
 	}
    
 	Pointer(int n)
    
 	{
    
 		if (n > 0) p = new int[n];//在堆区申请n个大小为int类型的变量
    
 		cout << "有参构造" << endl;
    
 	}
    
 };
    
  
    
 int main()
    
 {
    
 	Pointer p1;//在创建对象时编译器自动调用
    
 	Pointer p2(2);//调用有参构造 创建对象
    
 	Pointer p3();//编译器会认为是函数声明 Pointer是返回值类型 p3是函数名 ()是参数
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/uItAZ0omBhaTLWESUsj9pgvqbKzf.png)

构造函数的三种调用方式

复制代码
 int main()

    
 {
    
 	//构造函数的分类调用
    
 	/*
    
 	括号法 显示法 隐式转换法(构造函数前面加explicit可以屏蔽隐式转换)
    
 	*/
    
 	Pointer a();//括号法
    
  
    
 	//显示法
    
 	Pointer b = Pointer(2);
    
  
    
 	//隐式转换法
    
 	Pointer c = 2;//将int类型通过构造函数 隐式转换成Pointer类型 
    
  
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/M7xtKfu8S0TDQ9bwHj4JAnUd3qFO.png)
析构函数

性质:

  • 是用来释放成员变量指向的堆区内存 的 名字和类名相同前面加~
  • 没有参数和返回值 不能重载
  • 在释放对象时编译器自动调用构造函数,且只调用一次如果没有实现析构函数编译器会提供默认的析构函数
复制代码
 class Pointer

    
 {
    
 	int n;
    
 	int* p;
    
 public:
    
 	Pointer()
    
 	{
    
  
    
 	}
    
 	Pointer(int n)
    
 	{
    
 		this->n = n;
    
 		p = new int[n];
    
 	}
    
 	~Pointer()
    
 	{
    
 		if (p)delete[]p;
    
 	}
    
 };
    
  
    
  
    
 int main()
    
 {
    
 	Pointer p(4);//调用无参构造创建A类型的对象在堆区
    
 Pointer* p1 = new Pointer;//无参
    
 delete p1;
    
 Pointer* p4 = new Pointer[3]{ Pointer(1),Pointer(2) };
    
 delete[]p4;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/MTIok1UxENKeYgXqJh0bV28GO7iR.png)

delete先调用析构(内存空间)再调用free(free释放p自己)

new先调用malloc再调用构造函数

【注】当对象的生命周期结束时,析构函数会被自动调用

拷贝构造函数

定义:形参是本类对象的引用,通过已存在的对象初始化新的对象

拷贝构造参数必须是引用避免递归加const避免修改实参

常见的用处(调用时机):

  • 对象以值的方式作为函数参数
  • 对象以值的方式作为函数返回值
  • 使用已存在的对象初始化新的对象

如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作
如果用户定义了拷贝构造,编译器不会提供其他构造函数

  • 每个类都必须有一个拷贝构造函数。可以自己定义拷贝构造函数,用于按照需要初始化新对象;如果没有定义类的拷贝构造函数,系统就会自动生成一个默认拷贝构造函数 ,用于复制出与数据成员值完全相同的新对象。

编译器会提供默认的拷贝构造 浅拷贝 构造 拷贝构造 析构函数

复制代码
 #include<iostream>

    
 using namespace std;
    
  
    
 class A
    
 {
    
 public:
    
 	A() {};
    
 	A(const A& other)
    
 	{
    
 		cout << "拷贝构造" << endl;
    
 	}
    
 };
    
 A fun()
    
 {
    
 	A a;//调用无参构造
    
 	return a;
    
 }
    
 void fun(A a)
    
 {
    
  
    
 }
    
  
    
 int main()
    
 {
    
 	fun();
    
 	A a;
    
 	fun(a);
    
 	A b(a);//已存在的对象初始化新的对象
    
 	A c = a;//隐式类型转换调用构造函数
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/fwbpqxN3PjvBoS4rLds0mKny17Wg.png)
复制代码
 #include<iostream>

    
 using namespace std;
    
  
    
 class Person
    
 {
    
 public:
    
 	int age;
    
 public:
    
 	//无参构造
    
 	Person()
    
 	{
    
 		cout << "无参构造!" << endl;
    
 	}
    
  
    
 	//有参构造
    
 	Person(int a)
    
 	{
    
 		age = a;
    
 		cout << "有参构造" << endl;
    
 	}
    
  
    
 	//拷贝构造函数 参数为引用 避免递归 加const避免修改实参
    
     //构造函数拷贝自己这种东西叫拷贝构造
    
 	Person(const Person& p)
    
 	{
    
 		age = p.age;
    
 		cout << "拷贝构造" << endl;
    
 	}
    
  
    
 	//析构函数
    
 	~Person()
    
 	{
    
 		cout << "析构函数!" << endl;
    
 	}
    
 };
    
 void test01()
    
 {
    
 	Person p1(18);
    
 	//如果不写拷贝构造,编译器会自动添加拷贝构造,并且做浅拷贝操作
    
 	Person p2(p1);
    
  
    
 	cout << "p2的年龄为: " << p2.age << endl;
    
 }
    
  
    
 void test02()
    
 {
    
 	//如果用户提供有参构造,编译器不会提供默认构造,会提供拷贝构造
    
 	Person p1; //此时如果用户自己没有提供默认构造,会出错
    
 	Person p2(10); //用户提供的有参
    
 	Person p3(p2); //此时如果用户没有提供拷贝构造,编译器会提供
    
  
    
 	//如果用户提供拷贝构造,编译器不会提供其他构造函数
    
 	Person p4; //此时如果用户自己没有提供默认构造,会出错
    
 	Person p5(10); //此时如果用户自己没有提供有参,会出错
    
 	Person p6(p5); //用户自己提供拷贝构造
    
 }
    
  
    
 int main() {
    
  
    
 	test01();
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/XzZnjpA4DiLWHS5bPrRmTagy0vVq.png)

拷贝构造函数是通过已经存在的对象初始化新对象

1.什么时候会调用拷贝构造?

参数或返回值以值的方式传递时

2.参数是const A&other 万能引用,左值右值都可以接收

3.参数含有指针时用深拷贝,浅拷贝会导致内存泄漏,两个变量指向同一个位置,修改一个另一个也改变

深浅拷贝

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区申请新内存,进行拷贝操作

复制代码
 #include<iostream>

    
 using namespace std;
    
  
    
 class Person
    
 {
    
 public:
    
 	int age;
    
 	int* m_height = nullptr;
    
 public:
    
 	//无参构造
    
 	Person()
    
 	{
    
 		cout << "无参构造!" << endl;
    
 	}
    
  
    
 	//有参构造
    
 	Person(int a,int height)
    
 	{
    
 		this->age = a;
    
 		this->m_height = new int(height);
    
 		cout << "有参构造" << endl;
    
 	}
    
  
    
 	//拷贝构造函数 参数为引用 避免递归 加const避免修改实参
    
 	Person(const Person& p)
    
 	{
    
 		age = p.age;
    
 		this->m_height = p.m_height;//浅拷贝
    
 		this->m_height = new int(*p.m_height);//深拷贝
    
 		cout << "拷贝构造" << endl;
    
 	}
    
  
    
 	//析构函数
    
 	~Person()
    
 	{
    
 		cout << "析构函数!" << endl;
    
 		if (m_height)
    
 			delete m_height;
    
 	}
    
 };
    
  
    
 int main() {
    
 	//编译器会提供默认的拷贝构造 浅拷贝 析构函数
    
 	//拷贝构造就是简单的赋值
    
 	//浅拷贝:不同对象里面的指针类型成员变量指向同一块堆区内存,会造成一块内存
    
 	//多次释放编译器会报错,其中一个对象修改了内存另一个对象也会被修改
    
 	Person p(16, 4);
    
 	Person p1 = p;
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/aK9SmzCoMD1EFR4LcTsp8Nn3XIwW.png)
复制代码
 #include<iostream>

    
 #include<vector>
    
 #include<string>
    
 using namespace std;
    
  
    
 class Person
    
 {
    
 	int age;
    
 	int *m_height = nullptr;
    
 	string name;
    
 public:
    
 	Person() { cout << "无参默认构造" << endl; }
    
 	Person(int age,string name,int height)
    
 	{
    
 		this->age = age;
    
 		this->name = name;
    
 		this->m_height = new int(height);
    
 	}
    
 	//参数为引用 避免递归,加const 避免修改实参
    
 	Person(const Person& other)
    
 	{
    
 		this->age = other.age;
    
 		this->name = other.name;
    
 		//this->m_height = other.m_height;  浅拷贝
    
     //会导致两个对象里的两个成员变量指向同一个堆区内存,
    
     //一个对象修改,另一个也随之修改
    
  
    
 		//下面是深拷贝
    
 		this->m_height = new int(*other.m_height);
    
 	}
    
 	~Person()
    
 	{
    
 		cout << "析构函数" << endl;
    
 		if (m_height)
    
 		{
    
 			delete m_height;
    
 		}
    
 	}
    
 };
    
  
    
 int main()
    
 {
    
 	Person p(16,"张三",4);
    
 	Person p1 = p;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/1TMyGkmwuJdZbpOLQn5U7YeEX3i8.png)
初始化参数列表

初始化参数列表只能在构造函数中使用 ,是给成员变量初始化 的,初始化的顺序和参数列表的顺序无关,和成员变量的顺序一致(成员变量顺序决定初始化顺序),引用和常量在初始化参数列表中初始化

复制代码
 #include<iostream>

    
 using namespace std;
    
 class Person
    
 {
    
 	int P_a, P_b, P_c;
    
 	int& P_e;
    
 	const int P_f;
    
 public:
    
 	Person(int a, int b, int c) :P_a(c), P_b(P_c), P_c(c),P_e(a), P_f(b){};
    
 	void print()
    
 	{
    
 		cout << P_a << " " << P_b << " " << P_c << " " << P_e << " " << P_f;
    
 	}
    
 };
    
  
    
 int main()
    
 {
    
 	Person p(1,2,30);
    
 	p.print();
    
 	return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/HZ2Y9eKlITakjMfvs6LESWhzAoBt.png)
对象成员

类中的成员是其他一个类的对象,称该成员为 对象成员

构造顺序:对象成员的构造,在调用本类构造

析构顺序:与构造顺序相反

复制代码
 #include<iostream>

    
 using namespace std;
    
 const int N = 1e4 + 5;//数组的大小需要用常量定义
    
 int dt[N][N];
    
  
    
 class A
    
 {
    
 public:
    
 	A(int a)
    
 	{
    
 		cout << "A的构造" << endl;
    
 	}
    
 	~A()
    
 	{
    
 		cout << "A的析构" << endl;
    
 	}
    
 };
    
  
    
 class B
    
 {
    
     //没有无参构造,所以创建对象a要给个参数,在初始化参数列表初始化
    
 	A a;//构造函数是给对象初始化的,是给成员变量赋值的
    
 public:
    
 	B(int b):a(b)
    
 	{
    
 		cout << "B的构造" << endl;
    
 	}
    
 	~B()
    
 	{
    
 		cout << "B的析构" << endl;
    
 	}
    
 };
    
 int main()
    
 {
    
 	B b(2);
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/7x8esfmr106nJQSEOABVDIqPUgdR.png)
静态成员函数

特点:

  • 所有对象共享一个静态成员变量
  • 在编译阶段,主函数之前进行初始化
  • 在类内声明 类外初始化
  • 可以使用类名或对象名访问公有的静态成员变量
  • 在发生继承时,静态成员变量不会被继承,父类子类共享同一个静态成员
  • 静态成员变量不占对象的内存(静态成员变量在静态区,所有对象共同访问同一个)

静态成员变量在静态区,静态成员函数在代码区

  1. 静态数据成员的定义与普通数据成员相似,但前面要加上static关键字。
  2. 静态数据成员的初始化与普通数据成员不同。静态数据成员初始化应在类外单独进行,而且应在定义对象之前进行。一般在main()函数之前、类声明之后的特殊地带为它提供定义和初始化。
  3. 静态数据成员属于类(准确地说,是属于类中对象的集合),而不像普通数据成员那样属于某一对象,因此,可以使用“类名::”访问静态的数据成员。格式如下:类名::静态数据成员名。
  4. 静态数据成员与静态变量一样,是在编译时创建并初始化。它在该类的任何对象被建立之前就存在。因此,共有的静态数据成员可以在对象定义之前被访问。对象定以后,共有的静态数据成员也可以通过对象进行访问。
复制代码
 #include<iostream>

    
 using namespace std;
    
 class B
    
 {
    
 public:
    
 	B()
    
 	{
    
 		cout << "B的构造" << endl;
    
 	}
    
 };
    
  
    
 class A
    
 {
    
 public:
    
 	static int a;//类内声明 类外初始化
    
 	static B c;
    
 	int b = 0;
    
 	A()
    
 	{
    
 		a++;
    
 		b++;//所有对象共享同一个静态成员变量
    
 	}
    
 };
    
 int A::a = 0;
    
 B A::c = B();
    
 int main()
    
 {
    
 	A a, b, c, d;
    
 	cout << a.a <<" " << b.a <<" " << c.a <<" " << d.a << endl;
    
 	cout << sizeof(a) << endl;
    
 	A::a = 1;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/8hm0TDbwau2dHFc6oINWMsxKqOBt.png)
空指针访问成员函数
复制代码
 #include<iostream>

    
 #include<algorithm>
    
 using namespace std;
    
  
    
 class A {
    
     int a;
    
 public:
    
     void fun()
    
     {
    
         //this->a=3;
    
         cout << "work" << endl;
    
     }
    
 };
    
  
    
 int main()
    
 {
    
     //空指针可调用函数,但是函数中有静态成员变量时会报错
    
     //因为this是空指针
    
     A *a1=nullptr;
    
     a1->fun();
    
     return 0;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-17/SY7PbQIuRW83lJOChfXwAtreijkM.png)

全部评论 (0)

还没有任何评论哟~