IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 编程学习总结! -> 正文阅读

[C++知识库]C++ 编程学习总结!

一、C++ 概念

编译工具 g++   	源文件扩展名cpp		
//编译c++程序与C语言
#include <iostream>
using namespace std;

#include <stdio.h>

int main(int argc, char *argv[])
{
	cout << "hello world\n";
	printf("open\n");
}

二、C / C++的差异性

C语言是面向过 程编程,C++是面向对象编程。 

2.1、相对于C/ C++ 有更为严格的类型检查

2.2、常变量 const只读变量

C语言中 ,const修饰的变量的数值、不可以该变量改变、但是可以通过非 const指针修改。

此处:&a 的数据类型为 const int * 

c++中,const 修饰一个变量,表示该变量永远只读,只能使用,不能修改const 修饰的变量为只读变量

错误:c++ 有更为严格的类型检查,不能将 const int * 转换成 int *
//第一种差异性,常变量
#include <stdio.h>		
int main()
{
	/*
	C语言中,const修饰的变量的数值、不可以该变量改变、但是可以通过非 const指针修改。			
	*/

	const int a = 13;			
	//a += 12;
	int *p = (int *)&a;	//此处:&a 的数据类型为 const int * 
	
	*p += 3;
	
	printf("a: %d\n", a);
}
//第一种差异性,常变量
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
	/*
	c++中,const 修饰一个变量,表示该变量永远只读,只能使用,不能修改
	const 修饰的变量为只读变量
	*/	
	
	const int a = 13;
	//a++;
	
	//错误:c++ 有更为严格的类型检查,不能将 const int * 转换成 int *		
	//int *p = &a;	//error
	int *p = (int *)&a;
	*p += 3;
	
	cout << "a: " << a << endl;		//:13
}

2.3、强制类型转换

int b = int(a);			//c++中的类型强制转换
int c = int(a + b);		//c++中的类型强制转换
//第二种差异性,强制内型转
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
	double a = 13.1111;
	int b = int(a);			//c++中的类型强制转换
	int c = int(a + b);		//c++中的类型强制转换

}

2.4、变量的引用

引用:就是为已存在的变量,取别名,是一种新的数据类型。				
注意:
	1、取别名时,必须赋值,但不能为常量取别名。
	2、数据类型 & 变量名 = 变量;
	3、函数参数传参也可以使用 引用				
	4、在函数被调用时,才会启用形参取别名		
//第三种差异性,变量的引用
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{	
	/*引用:就是为已存在的变量,取别名,是一种新的数据类型。
	
	注意:
		1、取别名时,必须赋值。
		2、数据类型 & 变量名 = 变量;
		3、函数参数传参也可以使用 引用
	*/

	int a = 13;
	int &b = a;		//&b:引用;为a变量取别名
	
	//int &c = 123;	//error 不能为常量取别名
	
	cout << "&b: " << &b << endl;	//:&b: 0xbf8f6348
	cout << "&a: " << &a << endl;	//:&b: 0xbf8f6348
	
	b += 2;
	cout << "&a: " << a << endl;	//:&a: 15
	
	int c = 11;
	swap(a, c);						//:a c 同在一个存储空间
	cout << "a: " << a << "c: " << c << endl;	//:a: 11c: 15
}

void swap(int &x, int &y)	//在函数被调用时,才会启用形参取别名
{
	int tmp = x;
	x = y;
	y = tmp;
}

2.5、函数重载

对一个函数名重新赋予它的新含义,使一个函数名可以多用。						
c++中的函数重载,函数名相同,但参数列表必须不同
	1、参数个数不同
	2、参数个数相同、类型不同
	使用的时候看实参来调用
//函数重载和调用实列			
/*
	c++中的函数重载,函数名相同,但参数列表必须不同
		1、参数个数不同
		2、参数个数相同、类型不同
		使用的时候看实参来调用
	*/
	
#include <iostream>
using namespace std;

void sum()
{
	cout << "18\n";
}

void sum(int a)
{
	cout << "23\n";
}

void sum(int a, int b)
{
	cout << "28\n";
}

void sum(int a, int b, int c)
{
	cout << "33\n";
}

void sum(float a, float b)
{
	cout << "38\n";
}

int main(int argc, char *argv[])
{	

	int a = 13;
		
	sum();			//:18
	sum(12);		//:23
	sum(1, 3);		//:28
	sum(1, 3, 5);	//:33
	sum(float(1.1), float(1.2));	//:38	c++ 小数点默认double类型
}

2.6、默认参数

c++的函数可以带默认参数:
默认参数设置规则:
	1、只能在函数声明时,设置默认参数,定义时不能写默认值
	2、默认参数只能从参数列表的最右开始,依次往左赋值,否则error 中间不能跳跃。
注意:
	1、默认参数结合函数重载,在调用时,容易参数歧义(二义性)。
//函数默认参数
#include <iostream>
using namespace std;

int a;

int add()							//H 16
{
	cout << __LINE__ << endl;		//H 18
}

int add(int x = 5)					//H 21
{
	cout << __LINE__ << endl;		//H 23
}

int add(int x, int y, int z = 100)
{
	cout << __LINE__ << endl;		//H 28
}

int add(int x, int y, int &c = a)	// H 33
{
	cout << __LINE__ << endl;		//H 35
}

/*
	c++的函数可以带默认参数:
		默认参数设置规则:
			1、只能在函数声明时,设置默认参数,定义时不能写默认值
			2、默认参数只能从参数列表的最右开始,依次往左赋值,否则error 中间不能跳跃。
		注意:
			1、默认参数结合函数重载,在调用时,容易参数歧义(二义性)。
			2、如果要对引用类型的形参 赋值,那么必须使用以存在的 全局变量;对应33 H
*/

int main(int argc, char *argv[])
{	

	add(1, 2, 3);	//:28
	add(1, 2);		//:28
	
	add(6);			//:23
	//add();		//:	error	//有歧义的,16行和20行,编译器不知道该调用那行

}

2.7、内联函数

内联函数,只在声明时使用 inline 说明。
注意:
	1、频繁使用的函数
	2、函数代码语句很少(<= 5局)
	3、函数代码语句简单,没有控制语句(循环语句,switch)
目的:
	1、优点:提升代码运行效率;缺点:目标程序体积较大
//内联函数
#include <iostream>
using namespace std;

inline int add(int a, int b);	//声明一个内联函数

/*
	内联函数,只在声明时使用 inline 说明。
	注意:
		1、频繁使用的函数
		2、函数代码语句很少(<= 5局)
		3、函数代码语句简单,没有控制语句(循环语句,switch)
	目的:
		提升程序运行时的效率,缺点就是 目标程序体积变大
*/

int main(int argc, char *argv[])
{	
	cout << add(1, 2) << endl;		//:3
	//cout << add(1 + 2) << endl;	//:error
}

int add(int x, int y)	//内联函数的定义
{
	return x+y;
}

2.8、结构体

1、c++ 中为了保护数据的安全性,引入了访问权限限定符。
2、结构体变量初始化、引入了构造函数
3、释放结构体变量占用资源、引入了构造函数
//成员函数的访问使用 1
#include <iostream>
using namespace std;

/*
	c++中,为了保护数据的安全性。
		1、引入 访问权限限定符:public \ protected \private
		2、结构体 默认为 public 访问权限
		3、为了访问数据成员,引入成员函数
		4、由于成员函数也在 Demo 作用域中,所以在函数体内部可以直接使用 成员变量
		
*/

struct Demo{

public:								//公有的才有被访问的权限,才能够被外部结构体.号进行访问。
	void setValue(int a, int b);	//成员函数的声明
	int getX();
	int getY()
	{
		return y;
	}
	
private:							//访问权限限定符,私有的
	
	int x, y;						//x和y为私有成员变量(也被称为数据成员)
};

void Demo::setValue(int a, int b)	//成员函数的定义
{
	x = a;
	y = b;
}

int Demo::getX()
{
	return x;
}

int main(int argc, char *argv[])
{
	struct Demo obj;
	obj.setValue(1, 3);
	cout << obj.getX() << endl;		//:1
	cout << obj.getY() << endl;		//:3
}
//成员函数的访问使用 2
#include <iostream>
using namespace std;

/*
	c++中,为了保护数据的安全性。
		1、引入 访问权限限定符:public \ protected \ private
		2、结构体 默认为 public 访问权限
		3、为了访问数据成员,引入成员函数
		4、由于成员函数也在 Demo 作用域中,所以在函数体内部可以直接使用 成员变量
		5、当成员函数局部变量名与 成员变量名一致,引入特殊的 this 指针指向成员变量,区分局部变量和成员变量
		6、结构体的每一个成员函数都默认拥有 this 指针,该指针指向当前调用函数的结构体变量
		7、结构体变量的定义初始化,引入 构造函数:
			1、没有数据类型,也就是该函数没有返回值
			2、函数名与结构体名一致
			3、该函数不能被 结构体变量调用,只能在定义结构体变量时,被系统调用
		8、释放结构体变量占用的资源,引入 析构函数:	
			1、没有数据类型,也就是该函数没有返回值
			2、函数名 由 ~结构体名 构成 
			3、该函数不能有参数
			4、该函数不能被 用户调用,只能在结构体变量 生命周期 结束时被 系统调用,或者遇见 delete 时,系统调用			
*/

#define pri() cout<<__LINE__<<"func:"<<__func__<<endl;	//构造函数重载

struct Demo{

public:								//公有的才有被访问的权限,才能够被外部结构体.号进行访问。
	void setValue(int a, int b);	//成员函数的声明
	int getX();
	int getY()
	{
		return y;
	}

	/*构造函数*/	
	Demo()							//构造函数
	{
		pri();						//:45func:Demo		H45
	}
	
	Demo(int x)						//带参数构造函数
	{
		pri();
	}
	
	Demo(int x, int y)				//带参数构造函数
	{
		this-> x = x;									
		this-> y = y;
		pri();						//:55func:Demo		H55
	}
	/*构造函数*/
	
	 ~Demo()						//析构函数
	 { 
		pri(); 						//:69func:~Demo	调用了两次	因为有两个结构体变量,调用两次
									//	69func:~Demo

	 }
	
	
private:							//访问权限限定符,私有的
	
	int x, y;						//x和y为私有成员变量(也被称为数据成员)
};

#if 0
void Demo::setValue(int a, int b)	//成员函数的定义
{
	x = a;
	y = b;
}
#endif

void Demo::setValue(int x, int y)	//成员函数的定义
{
	cout << this << endl;			//0xbfd205b8	//参考第6点
	this-> x = x;									//参考第5点	
	this-> y = y;
}

int Demo::getX()
{
	return x;
}

int main(int argc, char *argv[])
{
	struct Demo obj;
	cout << &obj << endl;			//0xbfd205b8	//参考第6点
	
	obj.setValue(1, 3);
	cout << obj.getX() << endl;		//:1
	cout << obj.getY() << endl;		//:3
	
	/*结构体定义初始化,需要构造函数构造*/			//参考第7点	
	struct Demo obj1(2, 5);  		//结构体定义初始化 	      
	cout << obj1.getX() << endl;	//:2
	cout << obj1.getY() << endl;	//:5
}

三、内存模型及名字空间

3.1、作用域

局部域
		
名字空间域

类域

变量的作用域:
	局部变量
	全局变量

3.2、链接性

链接性:描述名称如何在各个单元中共享。
外部链接:名称可以在文件间共享
内部链接:名称仅仅能在一个文件中的函数共享。
//链接性
#include <iostream>
using namespace std;

int a = 100;

int add()	//内联函数的定义
{
	return a;
}

#include <iostream>
using namespace std;

int a = 100;

int main(int argc, char *argv[])
{	
	cout << a << endl;		//:100					
}
//外部链接
#include <iostream>
using namespace std;

int a = 100;

int add()	//内联函数的定义
{
	return a;
}

//使用外部链接、链接其他文件定义初始化好的全局变量
#include <iostream>
using namespace std;

extern int a;

extern int add();

int b = 13;
int c = 10;

int main(int argc, char *argv[])
{	
	cout << a << endl;		//:100	
	cout << add() << endl;	//:100	

	int b = 11;
	cout << b << endl;		//:11	//打印局部
	cout << ::a << endl;	//:13	//::作用域访问符

	extern int c;			//引用全局变量 c
	cout << c << endl;		//访问全局变量 c	//:10
	c+=1;					//使用全局变量 c
	cout << c << endl;		//:11
	cout << ::c << endl;	//:11
	
	//int c = 14;			//error	因为c变量被连接到了该函数,就不能在定义c
}
//c文件
#include <stdio.h>

int add(int x, int y)
{
	return x+y;
}
//编译:gcc -c add.c 
//编译得到一个add.o文件

//用链接c函数
#include <iostream>
using namespace std;

extern "C" int add(int, int);

int main(int argc, char *argv[])
{	
	cout << add(1, 3) << endl;		//:4	
}

//编译:g++ extern.cpp add.o

3.3、动态内存

1、new
		在堆区开辟一个空间
	
2、delete
	释放开辟的堆空间
//在堆区开辟一个空间	 运算符:new	delete
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{	
	int *p;
	p = new int;			//在堆区开辟一个int类型的空间,将1空间首地址给p指针
	*p = 13;
	
	cout << *p << endl;		//:13	
	
	int *q = new int(20);	//在堆区开辟一个int类型空间,初值为20
	
	cout << *q << endl;		//:20
	
	delete p;				//释放空间
	
	/*开辟一个数组空间*/
	int *buf = new int[5];	//在堆区开辟 数组空间,最多存5个int型元素
	buf[0] = 1;
	buf[1] = 2;
	
	cout << *(buf) << *(buf + 1) << endl;	//:1 2
	
	delete []buf;			//释放数组空间	
}

3.4、声明与作用域

1、声明区,可以进行声明的区域
		namespace	MySpace{	//给这片声明区取名字 MySpace
			
		}
		
2、名字空间	
	::			
	
3、潜在的作用域
	从声明点、到声明区结尾
//声明使用空间
#include <iostream>
using namespace std;

int a = 10;
int b = 20;

void demo()
{
	cout << __LINE__ << endl;	//:21	//H 29		
}

namespace MySpace{	//给这片声明区取名字 MySpace
	int a = 13;	

	void demo()
	{
		cout << __LINE__ << endl;	//:29	//H 29		
	}
}

namespace B{	//给这片声明区取名字 MySpace
	int b = 22;	

	void demo()
	{
		cout << __LINE__ << endl;	//:38	//H 38		
	}
}

int main(int argc, char *argv[])
{	
	cout << a << endl;	//:10
	
	//方式一 :声明使用名字空间中的变量
	using  MySpace::a;
	cout << a << endl;		//:13
	cout << a << endl;		//:13	//声明这个空间中的都会调用名空间里面变量
	
	cout << ::a << endl;	//:10
	
	//方式二:直接使用名字空间中的变量或函数
	using  MySpace::demo;	//声明此行及以后都是用 MySpace 中的 demo 函数
	demo();					//:29
	::demo();				//:21	//调用全局不知名的 demo 函数
	B::demo();				//:38	//使用 名字空间 B 中的函数 demo		

}

四、输入输出流

4.1、输出流

//输出流
#include <iostream>
//using namespace std;

int main(int argc, char *argv[])
{	
	//cout << "hello Word" << endl;				//:error
	std::cout << "hello Word" << std::endl;		//:hello Word
}
1、引用头文件:
	#include <iostream>
	using namespace std;
	
2、基本形式如下:
	cout << 表达式1 << 表达式2 << ...;
	
3、换行:
	控制符:endl
	换行符:\n

4、一个cout语句可以分写若干行
#include <iostream>
using namespace std;

int main (int argc, char *agv[])
{
	cout << "hello world" << endl;
	cout << "hello"
			"world"
		 << endl;
	return 0;
}
5、cout输出时,系统会自动判别输出数据的类型
#include <iostream>
using namespace std;

int main (int argc, char *agv[])
{
	int a 123:
	double b 456.789;
	char c= 'a';
	
	cout << a << b << c << endl;

	return 0;
}

4.1、输入流

1、引用头文件:
			#include <iostream>
			using namespace std;
			
2、基本形式如下:				
	cin >> 变量1 >> 变量2 >> ...;
#include <iostream>
using namespace std;

int main (int argc, char *agv[])
{
	int ival;
	char ch:
	cin >> ival >> ch
	cout << ival << ch << endl;
	return 0
}
3、换行:
	控制符:endl
	换行符:\n

4、一个cin语句可以分写若干行					

5、cout输入时,系统会自动判别输人数据的类型	

4.1、格式化控制符

//格式化控制符	1	
#include <iostream>
#include <iomanip>

using namespace std;

int main(int argc, char *argv[])
{
	int a = 50;
	float b = 50.01;
	char c = 50;
	
	cout << "a = " << a << "\n";			//:50
	cout << "b = " << b << endl;			//:50.01
	cout << "c = " << c << endl;			//:2
	
	cout << showpos << a << endl;			//:+50			//正整数前显示”+”符号
	cout << right << setw(8) << a << endl;	//:	+50		//输出数据在本域宽范围内右对齐
	cout << left << setw(8) << a << endl;	//:+50			//输出数据在本域宽范围内左对齐
	
	float d = 50.00;
	cout << showpoint <<  d << endl;		//:50.00		//浮点数输出带小数点
	
	cout << "hello"
			"world"
		 <<endl;							//:helloworld	//换行打印
	
}
//格式化控制符	2
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
	int i = 0;
	float f = 0;
	char c = 0;
	cout << "please input i:" << endl;
	
	cin >> i;									//:455		
	cout << "i = " << i << endl;				//:i = 455
	
	cout << "please input f and c:" << endl;
	cin >> f >> c;								//:564 42
	cout << "f = " << f << endl;				//:564
	cout << "c = " << c << endl;				//:42
	cout << "f = " << f << "c = " << c << endl; //:f = 56c = 4
	
}

五、对象和类

5.1、OPP思想

1、抽象:就是声明定义一个类,抽象概括一类对象的公共性质。
	数据抽象:设置成员变量
	代码抽象:设置成员函数
2、封装:将数据成员和成员函数结合在一起,形成一个整体,就是类体部分。

5.2、类的声明定义

1、类体中默认权限为:private	私有的

2、成员函数在类体之外的定义语法:
		数据类型 类名::函数名(<参数列表>){函数体}
		
3、成员变量的作用域:
	整个类的作用域(类域):类的所有成员函数的函数体区域

3、类的所有成员函数都有一个特殊的指针  this,指向 访问当前成员函数的对象

4、类:
		代码角度:用户自定义的数据类型,由class 进行说明
		抽象角度:对象的类型,是一批对象的共享和特征,是对象的抽象概括
5、对象:
		代码角度:就是一个变量
		抽象角度:具备行为和属性的事物,一切皆为对象,也就是类的具体实列
//类的使用
#include <iostream>
using namespace std;
/*
* 1、类体中默认权限为: private 私有的
* 2、成员函数在类体之外的定义语法:
*       数据类型 类名::函数名(<参数列表>){ 函数体 }
*
* 3、成员变量的作用域:
*       整个类的作用域(类域):类的所有成员函数的函数体区域
*
* 4、类的所有成员函数都有一个特殊的指针  this,指向 访问当前成员函数的对象
*
* 5、类:
*       代码角度:用户自定义的数据类型,由 class 进行说明
*       抽象角度:对象的类型,是一批对象的共性和特征,是对象的抽象概括
*
* 6、对象:
*       代码角度:就是一个变量
*       抽象角度:具备行为和属性的事物,一切皆为对象,也是类的具体实例
*
* 7、oop思想:面向对象编程思想。
*       1、抽象: 就是声明定义一个类,抽象概括出一类对象的公共性质
*           数据抽象: 设置成员变量
*           代码抽象: 设置成员函数
*
*       2、封装:将数据成员和成员函数结合在一起,形成一个整体,就是类体部分
*/

class Student;  //声明一个不完整的 Student 类

class Student{  //定义 Student 类
public:
	void setValue(char , int ); //在类体声明成员函数
private:
	char sex;
	int age;
};
void Student::setValue(char sex, int age) //成员函数的定义	//对应第2点
{
	/*类域的范围*/				//对应第3点
	this->sex = sex;			//对应第4点
	this->age = age;
}
int main(int argc, char *argv[])
{
	class Student stu;  //定义一个对象,实质是定义一个变量
	stu.setValue(1, 2); 

	class Student *stu1; //定义一个对象指针,实质是定义一个指针

	Student stu2;
	stu2 = stu;
	Student *stu3;
	
	stu1 = &stu;
	stu3 = new Student;  //new 开辟空间,也叫 new 一个新的对象

	stu1->setValue(2, 3);
}
6、如果设计一个类时,没有显示声明会自动生成:
	 - 构造函数 
	 - 析构函数 			
	 - 复制构造函数 			
	 - 赋值运算符 			
	 - 地址运算符	
//用类描述一个学生的信息
#include <iostream>
using namespace std;
#define pri() cout<<"line: "<<__LINE__<<endl;
class Student{
public:
	Student(){ pri(); }                     //默认构造函数的显式说明
	void setValue(int age, float weight){
		this->age = age;
		this->weight = weight;
	}
	int getAge(){
		return age;
	}
	float getWeight(){
		return weight;
	}
private:
	int age;
	float weight;
};
int main(int argc, char *argv[])
{
	Student stu;    //定义一个对象,采用默认构造,没有显式说明时,编译器自动生成
#if 1  
	stu.setValue(18, 120);
	Student stu1;
	stu1 = stu;     //默认赋值运算
	cout << stu1.getAge() << endl;	//:18

	Student *p;
	p = &stu;       //默认地址运算
	cout << p->getWeight() << endl;	//:120

	Student stu2 = stu1;    //默认的拷贝构造
	cout << stu2.getAge() << endl;	//:18

	Student stu3(stu1);     //默认的拷贝构造
	cout << stu3.getAge() << endl;	//:18

	Student *q = new Student;
#endif
}

5.3、构造和析构

1、构造
	构造函数的目的: 用来初始化对象
	特点:
	    1、默认构造函数没有显式说明时,会自动生成
	    2、构造函数没有数据类型,也就是没有返回值
	    3、构造函数函数函数名 与 类名一致
	    4、构造函数只能在定义对象时,被系统自动调用
	    5、构造函数可以重载
	    6、构造函数可以有默认参数
	    7、构造函数是类的 特殊成员函数
	    8、构造函数一般声明在 public 区域,也可以声明在 protected和private 区域形成限制构造						
//构造函数
#include <iostream>
using namespace std;
#define pri() cout<<"line: "<<__LINE__<<endl;

/*
* 构造函数的目的: 用来初始化对象
* 特点:
*       1、默认构造函数没有显式说明时,会自动生成
*       2、构造函数没有数据类型,也就是没有返回值
*       3、构造函数函数函数名 与 类名一致
*       4、构造函数只能在定义对象时,被系统自动调用
*       5、构造函数可以重载
*       6、构造函数可以有默认参数
*       7、构造函数是类的 特殊成员函数
*       8、构造函数一般声明在 public 区域,也可以声明在 protected和private 区域形成限制构造
*
* */
class Student{
public:
	Student(){ pri(); }             //构造函数的显式说明
	Student(int a){ pri(); }        //带参数的构造函数显式说明,此时无参数的构造函数将不会自动生成
	Student(Student &obj){ pri(); } //拷贝构造函数的显式说明
private:
	int age;
	float weight;
};
int main(int argc, char *argv[])
{
	Student stu;    		//定义一个对象,采用默认构造,没有显式说明时,编译器自动生成
	Student stu1(1);

	Student stu3(stu1);     //默认的拷贝构造
	Student stu2 = stu1;    //默认的拷贝构造

#if 1 
	Student *q = new Student;  //new 对象时,一定会构造函数
	q = new Student(2);
	q = new Student(stu);
#endif
}
2、拷贝构造
	1、浅拷贝:同类型的两个对象的成员指针,指向同一个堆区空间,两成员指针相互干扰
	
	2、深拷贝:同类型的两个对象的成员指针,指向两个不同的堆区,互不干扰		
//浅拷贝和深拷贝
#include <iostream>
#include <string.h>
using namespace std;
class Student{
public:
	Student(const char *name, int age);
	Student(Student &obj);
	char *getName();
	void setName(const char *name);
private:
	char *name;
	int age;
};
Student::Student(const char *name, int age)
{
	this->name = new char[ strlen(name) + 12 ];
	strcpy(this->name, name);
	this->age = age;
}
Student::Student(Student &obj)
{
#if 0
	this->name = obj.name;          				//浅拷贝:同类型的两个对象的成员指针,指向同一个堆区空间,两成员指针相互干扰
#else 
	this->name = new char[strlen(obj.name) + 1];    //深拷贝:同类型的两个对象的成员指针,指向两个不同的堆区,互不干扰
	strcpy(this->name, obj.name);
#endif
	this->age = obj.age;
}
char * Student::getName()
{
	return name;
}
void Student::setName(const char *name)
{
	strcpy(this->name, name);
}
int main(int argc, char *argv[])
{
	Student stu("张三", 18);
	Student stu1(stu);
	cout << "stu1: " << stu1.getName() << endl;

	stu1.setName("张三疯");
	cout << "stu1: " << stu1.getName() << endl;
	cout << "stu: " << stu.getName() << endl;
}
3、补充-考题	
//补充
#include <iostream>
using namespace std;

#define pri() cout<<"line: "<<__func__<<endl;
class A{
public:
	A(){ pri(); }
	A(A &obj){}
};
class B{
public:
	B() { pri(); }
};
class Demo{
public:
	B c;
	Demo(){ pri(); }
private:
	A a;
	A b;
};
int main(int argc, char *argv[])
{
	Demo obj;
}
4、析构函数
	1、析构函数:作用用来回收对象占用的资源
		特点:
		1、没有数据类型,也就是没有返回值
		2、函数名由 ~类名 构成
		3、析构没有参数和返回值,因此不能被重载。
		4、对象生命周期结束时,系统自动调用
		5、对象指针遇见 delete 时,系统自动调用
	
	2、包含对象成员(另一个类的对象最为改类的成员变量)的类对象的构造顺序;
		构造顺序:
			先对象成员构造,再对象构造
		析构顺序:
			先对象析构,再对象成员析构					
//析构函数
#include <iostream>
#include <string>

using namespace std;

/*
	析构函数:作用用来回收对象占用的资源
		特点:
		1、没有数据类型,也就是没有返回值
		2、函数名由 ~类名 构成
		3、析构没有参数和返回值,因此不能被重载。
		4、对象生命周期结束时,系统自动调用
		5、对象指针遇见 delete 时,系统自动调用
*/
/*
	包含对象成员(另一个类的对象最为改类的成员变量)的类对象的构造顺序;
		构造顺序:
			先对象成员构造,再对象构造
		析构顺序:
			先对象析构,再对象成员析构
*/
/*
	1、设计一个 Point 类描述坐标点,定义 p1点(0,4),p2点(3,0),
		计算两点之间直线距离
		cout << p1.dis(p2) << endl;	==> 5
*/

#define pri() cout << "line" << __LINE__ << endl;

class Base{	

public:
	Base()				//不带参数的构造函数
	{
		p = new char[12];
		pri();
	}
	
	~Base()				//析构函数
	{
		delete []p;		//释放堆区空间
		pri();
	}

private:
	char *p;	
	
};

int main(int argc, char *argv[])
{
	Base obj;
	//while(1);				//死循环析构函数不会调用
	Base *p = new Base;		//堆区空间不会随程序结束而结束,析构打印一次/构造打印两次
	
	delete p;				//析构/构造打印两次
}

5.4、this指针

this指针是一个特殊指针,指向类对象自身的首地址。	
练习:	设计一个 Point 类描述坐标点,定义 p1点(0,4),p2点(3,0),计算两点之间直线距离
		cout << p1.dis(p2) << endl;	==> 5
//计算两点之间直线距离
#include <iostream>
#include <cmath>
using namespace std;

class Point{

public:
	Point(){}
	Point(int a, int b)
	{
		x = a;
		y = b;
	}
	double Distance(Point a,Point b);
	
private:
	int x, y;
 
};
double Point::Distance(Point a,Point b)
{
	return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));
}
 
int main()
{
	Point point, p1(0,4), p2(3,0);
	
	cout << point.Distance(p1, p2);
}
#include <iostream>
using namespace std;
#include <math.h>

class Point{
public:
    Point(int x, int y)
    {
        this->x = x;
        this->y = y;
    }
    float dis(Point &obj)
    {
        return sqrt( (x-obj.x)*(x-obj.x) + (y-obj.y)*(y-obj.y) );
    }
private:
    int x, y;
};
int main(int argc, char *argv[])
{
    Point p1(3, 0), p2(0, 4);
    cout << p1.dis(p2) << endl;
}

5.5、static 修饰成员

1、静态成员变量
	1、在整个类域都可见,与具体的对象无关,
		static 改变了生命周期,可以作用类型的不同对象之间的数据传递。
	2、必须在类体之外定义初始化。

2、静态成员函数:
	1、声明时必须有 staic 关键字,定义时不能有 static。
	2、函数体中不能访问类的非静态成员。因为这里面没有this指针,也是语法规定的。
			
3、静态修饰对象:就是修饰一个变量,改变生命周期。			
//static 修饰成员
#include <iostream>
using namespace std;

class Base{

public:	
	static int z;
	Base(){}
	
	Base(int x, int y, int z)
	{
		this->x = x;
		this->y = y;
		this->z = z;
	}
	
	int getX()
	{
		return x;
	}
	
	static void setValue(int , int , int);	//静态成员函数的声明

	
protected:
	int y;
	
private:
	static int x;	//声明一个静态成员变量
 
};

int Base:: x = 13;	//静态成员变量必须在类体之外 定义初始化: 
					//语法:数据类型 类名::变量 = 初值
int Base:: z = 0;

void Base:: setValue(int x, int n, int z)	//静态成员函数的定义,不能有static
{
	//this->x = x;	//错误 静态成员函数与具体的对象无关,没有this指针
	Base:: x = x;
	
	y = n;
	
	//Base:: y = n;	//错误 静态成员函数,不能访问类的非静态成员
	Base:: z = z;
}

/*
	静态成员变量
		1、在整个类域都可见,与具体的对象无关,
			static 改变了生命周期,可以作用类型的不同对象之间的数据传递。
		2、必须在类体之外定义初始化。
	
	静态成员函数:
		1、声明时必须有 staic 关键字,定义时不能有 static。
		2、函数体中不能访问类的非静态成员。

*/

int main(int argc, char *argv[])
{
	Base obj(1, 2, 3);
	Base obj1;
	
	cout << obj1.getX() << endl;//:1
	
	//cout << Base::x << endl;	//:error,	x 	私有的
	cout << Base::z << endl;	//:3		z	为公有的,静态全局变量
	cout << obj1.z  << endl;	//:3	 	z	为公有的,说明静态成员变量与具体的对象无关

	Base::setValue(1, 2, 3);
	obj.setValue(2, 3, 4);
}

5.6、const 修饰成员

1、const 修饰成员变量,表示只读,必须在构造函数 参数初始化列表中赋初值
	1、参数初始化列表语法:		//只能在定义函数时写,声明时不能写
		
		类名(<形参列表>):成员变量(形参1),成员变量(形参2)...
		{}
		说明:
			1、程序在执行时,调用构造函数先执行参数初始化列表,然后才执行 构造函数体
	2、包含const 成员变量的类的所有构造函数都必须写出参数初始化列表,为只读变量赋初值。

2、const 修饰成员函数
	1、声明定义都必须使用 const 关键字
	2、表示不能使用该函数修改任何的成员变量,但是可以访问成员变量

3、const 修饰成员对象:
	1、表示该对象定义初始化之后,任何属性都不能更改
	2、const 修饰的对象不能访问类的非const 成员函数			
//const 修饰成员
#include <iostream>
using namespace std;

class Base{

public:	
	Base();
	Base(int x, int y) : x(x), y(y)
	{
		//this->x = x;	//error	,const 为修饰只读变量,只能用 : x(x), y(y)
		//this->y = y;		
	}
	
	int getX()
	{
		//x++;	//error	,x 为const 修饰只读变量
		return x;
	}
	
	int setValue(int x, int y) const;	//const 修饰成员函数
	
	int z;
		
private:
	const int x;
	int y;
};

Base::Base():x(0)	//对应第2点
{
	
}

int Base::setValue(int x, int y) const	//const 修饰成员函数,在内外定义时必须加 const
{
	//this->x = x;	//error	,x 修饰只读变量,只能用 : x(x), y(y)
	//this->y = y;	//error ,该函数为 const 修饰的函数,表示不能通过该函数修改任何成员数据
	int a = this->y;		//const 只能访问,不能修改
}

/*
	const 修饰成员变量,表示只读,必须在构造函数 参数初始化列表中赋初值
		1、参数初始化列表语法:
			类名(<形参列表>):成员变量(形参1),成员变量(形参2)...
			{}
			说明:
				1、程序在执行时,调用构造函数先执行参数初始化列表,然后才执行 构造函数体
		2、包含const 成员变量的类的所有构造函数都必须写出参数初始化列表,为只读变量赋初值。

	const 修饰成员函数
		1、声明定义都必须使用 const 关键字
		2、表示不能使用该函数修改任何的成员变量,但是可以访问成员变量

	const 修饰成员对象:
		1、表示该对象定义初始化之后,任何属性都不能更改
		2、const 修饰的对象不能访问类的非const 成员函数
*/

int main(int argc, char *argv[])
{
	#if 0
	Base obj(1, 3);
	
	cout << obj.getX() << endl; //:1
	#endif
	
	/* 定义const修饰的对象 */
	const Base obj;
	Base const obj1(1, 3);
	obj.setValue(0, 3);
	//obj.getX();				//error:const 对象只能访问类的 const 成员函数
	
	int x = obj.z;
}

5.7、友元

1、友元函数
			
	1、一个友元函数可以是多个类的有元函数,只需要在各个类中分别声明。

	2、友元函数: 就是在成员函数声明之前使用 friend 关键字说明,此时该函数就打破类的封装:
		1、友元函数不再是类的成员函数,不能通过对象 . 号访问,只能像普通函数调用一样使用
		2、友元函数的函数体中,没有类体的访问权限限定,也就是可以直接通过 对象.号 访问非静态成员,可以通过 类名::静态成员
		3、友元函数如果没有类类型作为形参,那么必须在类的外部进行定义,否则声明定义都可以在类体中
		4、友元函数必须声明在类体中			
//友元函数
#include <iostream>
using namespace std;
class Base{
public:
	Base(int x):x(x){}
	friend int getValue(Base &obj)//声明定义一个友元函数,表示该函数打破类的封装,不再是该类的成员函数,也就是 没有 this 指针
	{      
		return obj.x; //该友元函数打破了类的封装,也就是在该函数体中,没有权限限定
	}
	friend int getX();
private:
	int x;
	static int y;
};
int Base:: y = 13;

int getX()          //友元函数在类外部定义,就像普通函数定义一样
{
	Base obj(3);
	obj.x = 5;      //该友元函数打破类的封装,也就是没有 protected 和 private 的限制
	return Base::y;
}
/*
* 友元函数: 就是在成员函数声明之前使用 friend 关键字说明,此时该函数就打破类的封装:
*       1、友元函数不再是类的成员函数,不能通过对象 . 号访问,只能像普通函数调用一样使用
*       2、友元函数的函数体中,没有类体的访问权限限定,也就是可以直接通过 对象.号 访问非静态成员,可以通过 类名::静态成员
*       3、友元函数如果没有类类型作为形参,那么必须在类的外部进行定义,否则声明定义都可以在类体中
*       4、友元函数必须声明在类体中
* */
int main(int argc, char *argv[])
{
	Base obj(12);
	cout << getValue(obj) << endl;	//:12
	cout << getX() << endl;			//:13
}
2、友元类
	1、友元关系不能被继承
	
	2、友元关系是单向的,不具有交互性。
	
	3、如果 B 是 A 的友元类,也就是 A 将 B 当成朋友:
			那么在 B 类的所有成员函数中将 打破 A 类的权限。				
//友元类
#include <iostream>
using namespace std;
//class B;
class A{
public:
	A(int x, int y):x(x){}

	friend class B;             //说明 B是 A 的友元类,也就是A类将 B 类当成朋友
private:
	int x;
	static int y;
};
int A::y = 13;
class B{
public:
	int getY()
	{
		A obj(1, 2);
		obj.x = 3;
		return A::y;
	}
	int getX(A &obj)
	{
		return obj.x;
	}
};
/*
* 如果 B 是 A 的友元类,也就是 A将B 当成朋友:
*   那么在B 类的所有成员函数中都将 打破A 类的权限封装
* */
int main(int argc, char *argv[])
{
	A a(3, 4);
	B b;
	cout << b.getY() << endl;
	cout << b.getX(a) << endl;
}
3、有元成员函数		

	1、B类的成元函数可以是类A的友元		
//有元成员函数
#include <iostream>
using namespace std;

class A;
class B{
public:
		int getX(A &obj);		
		int getY(A &obj);
};

class A{	
public:	
	A(int x):x(x){}
	friend int B::getX(A &);	//说明 B 类的getX成员函数是A类的友元,也就是getX函数打破A类的封装
	
private:	
	int x;			
	static int y;
	
};

int A::y = 15;

int B::getX(A &obj)
{
	obj.y = 11;
	return obj.x;
}

int B::getY(A &obj)
{
	//obj.x = 15;				//错误,因为该函数不是A类的友元,没有打破A类的封装。	
	//return obj.x;
}


int main(int argc, char *argv[])
{

}
练习:
	// 思考:
	//      1、友元类和友元成员函数中,构造、析构的执行顺序
	//      2、设计一个Point类,定义 p1(3, 0), p2(0, 4),
	//          cout << dis(p1, p2) << endl; 求两点之间的直线距离
	//      3、分别定义一个类A和类B ,各有一个私有整数成员变量通过构造函数初始化;
	//         类A有一个成员函数Show(B &b)用来打印A和B的私有成员变量,
	//         请分别通过友元成员函数和友元类来实现此功能。		
1、友元类和友元成员函数中,构造、析构的执行顺序先被调用的构造函数,
其对应(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用。
/*2、设计一个Point类,定义 p1(3, 0), p2(0, 4),
					cout << dis(p1, p2) << endl; 求两点之间的直线距离*/

#include <iostream>
#include <cmath>
using namespace std;

class Point{

public:
	Point(){}
	
	Point(int x, int y)
	{
		this->x = x;
		this->y = y;
	}
	friend double dis(Point x, Point y);
 
private:
	int x, y;
	
};

double dis(Point x, Point y)
{
	return sqrt( pow(x.x-y.x, 2) + pow(x.y-y.y, 2) );
}
 
int main()
{
	Point p1(3, 0), p2(0, 4);
	
	cout << dis(p1, p2) << endl;
}
/*3.1、分别定义一个类A和类B ,各有一个私有整数成员变量通过构造函数初始化*/
#include <iostream>
using namespace std;
class B;
class A{
public:
	A(int x):x(x){}
	void Show(B &);
private:
	int x;
};
class B{
public:
	B(int x):x(x){}
private:
	friend void A::Show(B &);
	friend class A;
	int x;
};
void A::Show(B &b)
{
	cout << "A: " << x << endl; 
	cout << "B: " << b.x << endl;
}
int main(int argc, char *argv[])
{
	A a(2);
	B b(4);
	a.Show(b);
}

六、运算符重载

运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型

不能被重载的运算符
	逗号"."		?号表达式"?:"		sizeof		作用域"::"

6.1、成员运算符重载函数

函数体中有this指针指向第一个操作数,重载函数的形参个数 = 操作数 - 1;除了b++或b--	
//成员运算符重载函数
#include <iostream>
using namespace std;

class Base{
public:
	
	Base(int x) : x(x){}
	int operator+(int a)
	{
		return x + a;
	}
	
	int operator-(int a);
	
	int operator++(int )
	{
		return x++;
	}
	
	int operator++()
	{
		return ++x;
	}

private:
	int x;
	
};

int Base::operator-(int a)
{
	return x - a;
}

/*
	成员运算符重载函数,函数体中有this指针指向第一个操作数,重载函数的形参个数 = 操作数 - 1;除了b++或b--

*/

int main(int argc, char *argv[])
{
	 
	Base b(3);
	int a = b + 2;			// <==>	int a = b.operator+(2);
	cout << a << endl;		//:5
	
	//a = b - 1;			// <==>	a = b.operator-(1);
	a = b.operator-(2);		// <==>	上一步	
	cout << a << endl;		//:1
		
	cout << b++ << endl;	//:3
	
	cout << ++b << endl;	//:5
	
	//cout << 2 + b << endl;
}

6.2、友元运算符重载函数

函数体中没有this指针指向第一个操作数,重载函数的形参个数 = 操作数;除了b++或b--
重载函数的第一个形参,表示第一个操作数	
//友元运算符重载函数
#include <iostream>
using namespace std;

class Base{
public:
	
	Base(int x) : x(x){}
	friend int operator+(int a, Base &b)
	{
		return a + b.x;
	}
	
	friend int operator++(Base &obj, int);	//	int 占位符,后++
	
	friend int operator-(Base &b, int a)
	{
		return b.x - a;
	}
	
	friend ostream & operator<<(ostream &out, Base &obj)
	{
		out << obj.x;
		return out;
	}
	
	friend istream & operator>>(istream &in, Base &obj)
	{
		in >> obj.x;
		return in;
	}
	
	int operator()();	//成员
	
private:
	int x;
	
};

int operator++(Base &obj, int)
{
	return obj.x++;
}

int Base::operator()()	//成员
{
	return x;
}

/*
	友元运算符重载函数,函数体中没有this指针指向第一个操作数,重载函数的形参个数 = 操作数;除了b++或b--
		重载函数的第一个形参,表示第一个操作数
*/

int main(int argc, char *argv[])
{
	 
	Base b(3);

	cout << 2 + b << endl;		//:5
	
	cout << b++ << endl;		//:3
	
	cout << b - 2 << endl;		//:1
	
	cout << b << endl;			//:4	<==>	operator << (cout, b) << endl;
	
	Base a(1);
	cin >> a >> b;				//:2	4
	cout << "a: " << a << "b: " << b << endl;	//:a: 2 b: 4

	cout << a() << endl;		//:2	防函数:类对象模仿函数功能
								//a():	重载了()运算符,模拟函数功能,称为防函数
	
}
//防函数写法
#include <iostream>
using namespace std;

class Base{
public:
	
	Base(int x) : x(x){}
	
	int operator()();
	
	int operator()(int a);	//防函数写法
	
private:
	int x;
	
};


int Base::operator()()		//成员
{
	return x;
}

int Base::operator()(int a)	//防函数写法
{
	return x + a;
}

int main(int argc, char *argv[])
{
	 
	Base obj(10);

	cout << obj() << endl;	//:10	a():	重载了()运算符,模拟函数功能,称为防函数
	
	cout << obj(5) << endl;	//:15
	
}

6.3、函数数据类型

1、一般情况下,由返回值决定。
2、返回类的成员变量,并且期望返回之后能改变成员变量的数值,则返回引用类型。
练习:
	1、设计 Mytring 类,模仿string 类			
	/*	std::operator+–字符串连接
		std::operator!=–不等比较
		std::operator==–相等比较
		std::operator<–小于比较
		std::operator<=–小于等于比较
		std::operator>–大于比较
		std::operator>=–大于等于比较
		std::operator<<–字符串内容写到输出流中
		std::operator>>–从输入流中读取一个字符串
			 operator[] 括号运算,取某个字符
			 operator() 
	*/
    2、设计链表类, +号表示,链表尾部插入数据, -号表示尾部删除数据

	3、重载 ->*new[] 三个运算符

七、模板

八、类继承

九、多态

十、异常

十一、转换函数

十二、智能指针

跳转:上一篇、网络编程学习总结!

跳转:上一篇、网络编程学习总结!

跳转:C++ 理论概念知识总结!

跳转:C++ 理论概念知识总结!

持 续 更 新 中 . . .

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:15:53  更:2021-07-24 11:16:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/8 1:19:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码