当前位置: 首页 > article >正文

C++对C的拓展-3.22笔记

全部代码在VS中完成
在哔哩哔哩学习的这个老师的C++面向对象高级语言程序设计教程(118集全)讲的很不错(真的!!!),C语言也是在这个老师的带领下学习的

#include<iostream>
using namespace std;
//在局部要访问全局变量要加作用域::
int num = 10;
void test01(){
	int num = 20;
	cout << "局部变量num=" << num << endl;
	cout << "全局变量num=" << ::num << endl;
}

//命名空间
/*命名空间只能在全局范围定义
* 命名空间可以嵌套命名空间A::B::a
* 命名空间是开放的,可以随时把新的成员加入已有的命名空间
*/
namespace A {
	int data1 = 50;
}
namespace B {
	int data1 = 60;
}
void test02() {//加作用域是最安全最简单的方法
	cout << "输出A中的data1:" << A::data1 << endl;//50
	cout << "输出B中的data1:" <<B::data1 << endl;//60
}


//控制输出数的精度要用以下格式
//#include<iomanip>
//cout<<fixed<<setprecision(4)<<endl;



//声明和实现可分离
//命名空间只是整体的框架,所以函数的实现不用在命名空间中,只是申明一下
namespace C {
	int a;
	void set_a(int data);
	int printf_a(void);
}
void C::set_a(int data) {//函数在外面实现时需要加作用域
	C::a = data;
}
int C::printf_a(void) {
	return C::a;
}
void test03(){
	C::set_a(520);
	cout << "a = " << C::printf_a() << endl;
}



//无命名空间
//之前访问全局变量时使用::就是使用的一整个无命名空间
//内部连接只能在当前源文件用
//外部连接可以在外部源文件使用



//命名空间别名
namespace longlongname {
	int a = 456;
	void put(void) {
		cout << "helloworld" << endl;
	}
}
void test04() {
	namespace stortname = longlongname;//赋值语句
	cout << "longlongname::a=" << stortname::a << endl;
	longlongname::put();
	stortname::put();
}



//using修饰命名空间里面的某些数据或方法
namespace D {
	int prameA = 12;
	int prameB = 55;
	void fun_A() {
		cout << "hello fun_A" << endl;
	}
	void fun_B() {
		cout << "hello fun_B" << endl;
	}
}
void test05() {
	//使用作用域::
	cout << "D::prameA=" << D::prameA << endl;
	cout << "D::prameB=" << D::prameB << endl;
	//使用using
	using D::prameA;//表示以后使用D中的prameA
	using D::fun_A;//表示以后使用D中的fun_A
	fun_A();
	cout << prameA << endl;
	//使用using如果有同名的会造成二义性
}


//using声明碰到函数重载
//函数名相同,但是函数参数不同即一个函数名多种方法叫做函数重载,多态的体现
//c++三大特性:封装,继承,多态
//如果命名空间包含一组用相同名字重载的函数,using声明就声明了这个重载函数的所有集合



//using修饰整个命名空间
namespace E {
	int a = 105;
	int b = 2;
	int c = 3;
}
void test06() {
	using namespace E;
	//表示之后所有都使用E这个命名空间的内容
	//强调的是命名空间名

	//先查看当前普通变量a,如果没有再查看命名空间有没有a
	cout << a << endl;
	int a = 88888;
	cout << a << endl;//就近原则
	cout << b << endl;
	cout << c << endl;
}



//全局变量检测增强
/*在C语言中
* int a=10;有赋值当做定义
* int a;没有赋值当作申明
*/
/* 在C++中
* 申明必须要用extern
* extern int a;
*/




//C++中所有变量和函数必须有类型
/*在C语言中
* int fun1(i){}
* 其中i没有类型,可以是任何类型
* int fun2(){}
* 其中没有写参数,代表可以传任何类型的实参,只是接收不了,因为没有形参
*/
/*在C++中不可以这样
*/




//严格的类型转换
//在C++中不同类型一般不能直接赋值(基本数据类型可以,但是指针类型不可以),需要相应的强制转换




//struct(结构体)类型加强
/*1.C++中定义结构体类型的时候可以不加struct
* C语言:struct student Bob;
* C++语言:struct Bob;
* 2. C++中结构体成员可以是函数,而C语言不行
*/
struct student {
	int id_num;
	void set_num(int data) {
		id_num = data;
	}
};
void test07(){
	student Bob;
	Bob.set_num(158);
	cout << "id_num = " << Bob.id_num << endl;
}



//新增bool类型
//bool的变量只能赋值为true(非零)false(0)
void test08() {
	bool num;
	num = true;
	cout << "true = " << true << endl;
	cout << "false = " << false << endl;
}


//三目运算符功能增强
/*C语言中的三目运算符
*a>b ? a:b
* 返回的是a或者b的值
*/
//在C++中三目运算符返回的是a或b的引用(变量名)
void test09(){
	int a = 58;
	int b = 69;
	(a > b ? a : b) = 33;
	cout << "a = " << a << "b = "<< b <<endl;
}



//const增强(重要)
/*
在C语言中const修饰的是不变的变量而不是常量
既然是变量那么系统就会为它开辟空间
解释以下const int arrsize=10;
int arr[arrsize];在C语言中会报错
因为int arr[arrsize];在编译阶段系统就要为数组开辟空间,此时系统还不知道arrsize多大
而赋值这个动作要在运行阶段才可以完成,所以数组的元素个数不可以用变量名
*/
//C++的const
//1.C++中如果使用常量初始化const的变量,那么该变量就是符号常量并且放入符号常量表中
//const int num=10;这里的num是符号常量,被放入符号常量表中,num没有空间
//如果这时对num取地址,系统才会为num开辟空间,此时num才会变成变量
void test10() {
	const int num = 50;
	int* p = (int*)&num;//必须强制类型转化,或者写成const int* p=&num;
	*p = 77;
	cout << "*p = " << *p << endl;//结果为77,因为*p修改了空间内容
	cout << "num = " << num << endl;//结果为50,因为num这个变量名已经存在在符号常量表中,只要你取num这个变量名,那么就会在符号常量表中取找
}
//2.如果用普通变量初始化const修饰的变量,系统会立即为const修饰的变量开辟空间(就没有了符号常量表)
/*
* int a=66;
* const int p=a;
*/
void test11() {
	int a = 98;
	const int num = a;
	int* p = (int*)&num;
	*p = 77;
	cout << "*p = " << *p << endl;//77
	cout << "num = " << num << endl;//77
}
//3.const修饰全局变量a,如果使用常量初始化,那么变量a被分配到文字常量区,不在全局区,不可以进行赋值,赋值会发生段错误
//4.const如果修饰的是自定义数据类型(结构体,枚举,共用体)的变量,直接开辟空间
struct stu {
	int num;
	char name[32];
};//结构体结尾需要加分号
void test12() {
	const stu Bob = { 500,"Bob" };
	stu* p = (stu*)&Bob;
	p->num = 600;
	cout << Bob.name << Bob.num << endl;
}
//5.尽量以const替换宏(#define MAX 100;)
//const有类型,可以进行编译器安全检查,如果出错会爆出MAX这个名字,而#define无类型,不可以进行类型检查(出错只会出现100这个值)不好检查哪里出错
//const有作用域,而#define不重视作用域,不能作为类的成员,破坏封装性,不符合C++的特性




//在C++中能用引用(给变量名取个别名)绝不用指针(重要)
//1.编译器不会为别名开辟新的空间,但是使用指针就必须要为指针开辟空间,所以使用别名可以提高空间利用率
/*格式(给num取个别名为b)
* int num=10;
* int &b=num;//&不是取b的地址,只是描述b是num的别名
*/
//别名一般运用于函数传参,既可以将数传递进去,又可以节约空间
/*取别名的步骤
* 1.1.&修饰别名
* 1.2.要对那个变量取别名,就定义那个变量
* 1.3.从上往下整体替换
*/
void test13() {
	int a = 15;
	int& b = a;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	//a和b占用同一份空间
	cout << "&a = " <<&a << endl;
	cout << "&b = " << &b << endl;
}
void test14() {
	int arr[5] = { 1,2,3,4,5 };
	int (&new_arr)[5] = arr;//要加小括号,因为中括号的优先级最大
	cout << "arr[2] = " << arr[2] << endl;
	cout << "new_arr[2] = " << new_arr[2] << endl;
	//a和b占用同一份空间
	cout << "&arr = " << &arr << endl;
	cout << "&new_arr = " << &new_arr << endl;
}
//2.引用必须初始化
//int &b;//非法的
//3.引用一旦确定是谁的别名就不能更改
//4.引用作为函数参数,可以替代指针变量
void swap_int01(int a1, int b1) {//值传递
	int temp = a1;
	a1 = b1;
	b1 = temp;
}
void swap_int02(int *a1,int *b1) {//使用指针
	int temp = *a1;
	*a1 = *b1;
	*b1 = temp;
}
void swap_int03(int &a1, int &b1) {//使用引用
	int temp = a1;
	a1 = b1;
	b1 = temp;
}
void test15() {
	int a = 1;
	int b = 2;
	cout << "a = " << a << ",b = " << b << endl;
	swap_int01(a, b);//失败,因为传的值,而不是地址,没有办法将函数外免得值交换
	cout << "1.a = " << a << ",b = " << b << endl;
	swap_int02(&a, &b);
	cout << "2.a = " << a << ",b = " << b << endl;
	swap_int03(a, b);
	cout << "3.a = " << a << ",b = " << b << endl;
}
/*引用的好处
* 1.函数内部直接通过引用操作外部变量的值
* 2.省去了指针的操作
* 3.函数形参不会用于新的空间(节约空间)
*/



//常引用
//不能通过a修改空间的值
void test16() {
	//给10这个不变常量取个别名
	//int &a=10//不可以,因为a是int,而10是const int
	//int &a=(int)10//也不可以C++是强语法
	const int& a = 10;
	cout << "a =" << a << endl;
}
//常引用的运用场景:常引用作为函数参数即节约了空间,又防止了函数内部修改外部空间变量的值
void printf_data(const int a) {
	//此时在函数内部就不可以修改在外部作为变量的值
	cout << "num = " << a << endl;
}
void test17() {
	int num = 10;
	printf_data(num);
}



//引用作为函数的返回值类型(非常重要)
//1.通过函数返回值在外界操作函数内部申请的空间(在C语言中是通过返回一个指针从而控制函数内部变量)
int& get_data(void) {
	static int data = 999;
	//不要返回普通局部变量的引用,因为在函数执行完成之后会释放空间,不可以对一个非法空间取别名,会出现段错误
	//加一个static修饰,生命周期更长
	return data;//返回什么就是给谁取别名
}
void test18() {
	int& a = get_data();//用什么接就是给返回值取了什么别名
	cout << "a = " << a << endl;
}
//2.引用作为函数的返回值类型,可以完成链式操作
struct print {
	print& printf_int(print& ob, int value) {
		cout << value << endl;
		return ob;
	}
};
void test19(){
	print obj;
	obj.printf_int(obj, 10).printf_int(obj, 20).printf_int(obj, 30);
	//obj.printf_int(obj, 10)返回的是ob,然而obj=ob,所以拼接上去就可以无限下去
}



//引用的本质是常量指针
/*int a=10;
* int &b=num;的低层实现
* int * const b=&num;//const修饰变量名表示之后不可以随便改变指针的指向,b(地址)只读,*b指向的空间内容可读可写
*/




//指针变量的引用
void test20() {
	int num = 999;
	int* p = &num;//取别名的步骤,1.&修饰别名 2.要对那个取别名就定义那个变量 3.从上往下整体替换
	int*& new_p = p;
	cout << " *p = " << *p << endl;
	cout << "*new_p = " << *new_p << endl;
}
//实际运用(给p开辟空间让p指向)
void get_memory01(int** p1) {//int **p1=&p;
	//*p1==p
	*p1 = (int*)calloc(1, sizeof(int));
	**p1 = 100;
}
void get_memory02(int* &p1) {//int* &p1=p;
	//p1==p;
	p1 = (int*)calloc(1, sizeof(int));
	*p1 = 100;
}
void test21() {
	int* p = NULL;
	//get_memory01(&p);
	get_memory02(p);
	cout << "*p = " << *p << endl;
}




//内联函数(inline修饰的函数)(在编译阶段完成替换)(在函数定义的位置加上inline才可以,申明时加上不可以)
inline int myAdd(int x,int y) {
	return x + y;
}
//1.内联函数为了继承宏函数的效率,没有函数的开销,然后又可以像普通函数那样,可以进行参数返回值类型的安全检查,又可以作为成员函数
/*
*2.内联函数特点
* 2.1.能保证参数的完整性
* 2.2.有作用于的限制,可以成为类的成员
* 2.3类中的成员函数默认都是内联函数(不用inline)
*/
/*
* 3.宏函数和内联函数的区别:
* 宏函数:
* 预处理阶段完成替换,没有出入栈的开销,不能保证参数完整性,没有作用域限制,不能作为类的成员
* 内联函数:
* 编译阶段完成替换,没有出入栈的开销,能保证参数完整性,有作用域限制,能成为类的成员
*/
/*
*4.以下情况编译器不会考虑将函数进行内联编译(内联函数只是对编译器的一个建议):
* 在函数中不能存在任何形式的循环语句,不能存在过多的的条件判断语句,函数体不能过于庞大,不能对函数精心取地址操作
*/





//默认参数(缺省参数)(了解)
//1.C++在申明函数原型时可为一个或两个参数指定默认(缺省)的参数值,当函数调用的时候如果没有传参,编译器会自动用默认值代替
int my_add(int a,int b = 100) {//如果函数调用时,不给函数b传参,那么b的值为100
	return a + b;
}
void test22() {
	cout << "my_add(10,20) = " << my_add(10, 20) << endl;
}
/*2.函数默认参数从左往右,如果一个参数设置了默认参数,那么这个参数之后的参数都必须设置默认参数
*int fun(int a,int b=500,int c=50){}可以
*int fun(int a=95,int b=66,int c=50){}可以
*int fun(int a,int b,int c=50){}可以
*int fun(int a,int b=99,int c=50){}不可以
*/
//3.要在申明处设置默认值(一个函数可能在不同的文件中使用,即不同的场景,需要的默认值不一定相同,而在不同文件中使用函数时需要有申明,此时设置默认函数最为合适)




//函数的占位参数(了解)
/*
* 1.1.C++在申明函数时,可以设置占位参数
*1.2.占位参数只有参数类型声明,而没有参数名申明
*1.3一般情况下,在函数内部无法使用占位参数
* 1.4占位参数可以设置为缺省参数(默认参数处在传参时可以少传)
* void testfun(int a,int b,int=100){}
* 1.5什么时候用占位参数,在后面的操作重载的后置++要用到这个
*/
void testfun(int a,int b,int){
	cout<<"a + b = "<<a + b <<endl; 
 }
void test23() {
	testfun(10, 20, 30);
}




//函数的重载(多态的体现)(重要)
//1.函数的重载条件:函数名相同,函数个数,函数类型,函数顺序可以不同,就可以重载
void Fun(int a) {
	cout << "int : a = " << a << endl;
}
void Fun(int a,int b) {//函数个数不同
	cout << "int int : a = " << a <<", b = "<< b << endl;
}
void Fun(int a, float b) {//函数类型不同
	cout << "int float : a = " << a << ", b = " << b << endl;
}
void Fun(float a, int b) {//函数顺序不同
	cout << "float int : a = " << a << ", b = " << b << endl;
}
void test24() {
	Fun(10);
	Fun(10, 20);
	Fun(10, 20.1f);
	Fun(10.1f,20);
}
//2.返回值类型不同不可以占位重载条件
//3.函数重载和缺省参数同时出现,一定要注意二义性(ambiguous)
void fun01(int a) {
	cout << "int : a = " << a << endl;
}
void fun01(int a,int b=100) {
	cout << "int int : a = " << a <<", b = " << b << endl;
}
void test25() {
	//fun01(50);会出错,这个会找到两个函数,不知道该调用哪一个
	fun01(20, 30);
}
/*4.函数重载的原理
* 在C语言中,函数的入口地址是函数名决定
* 在C++中,函数的入口地址是由函数名和函数个数,顺序,类型共同决定的(编译器会将同名并且其他不同的函数修改成不同的函数名,这样就不会违背C语言的底层逻辑,函数名就代表函数入口地址)
*/
int main(int argc, char* argv[])
{
	test25();
	return 0;
}

http://www.kler.cn/a/599768.html

相关文章:

  • JAVA学习*Object类
  • python3面试题23个(设计模式、面向对象、正则)
  • Typora安装使用教程 简单易用的Markdown编辑器
  • 解决思科交换机无法访问局域网外设备
  • C++学习之路,从0到精通的征途:string类
  • 深入理解Spring框架:核心概念与组成剖析
  • C++题目
  • uv - reference [官方文档翻译]
  • 【嵌入式学习2】内存管理
  • GitLens with `Commit Graph`
  • 使用Python调用Jenkins Api之获取构建日志使用说明文档
  • 两个手机都用流量,IP地址会一样吗?深入解析
  • Excel第41套全国人口普查
  • 在Spring Boot中,可以通过实现一些特定的接口来拓展Starter
  • 安全上网沙箱:多方面解决政企私的上网问题
  • 2025-如何创建自己的电商网站
  • Linux 系统关机和重启指令
  • Spring Boot项目快速创建-开发流程(笔记)
  • JAVA_数据结构_栈和队列
  • CSS 中text - shadow和box - shadow原理、属性的使用方法及区别