C++核心编程Day01

1.作用域运算符

	作用域运算符可以用来解决局部变量与全局变量的重名问题,即在局部变量的
作用域内,可用::对被屏蔽的同名的全局变量进行访问。
//全局变量
int a = 10;
//1. 局部变量和全局变量同名
void test(){
	int a = 20;
	//打印局部变量a
	cout << "局部变量a:" << a << endl;
	//打印全局变量a
	cout << "全局变量a:" << ::a << endl;
}

2.命名空间

2.1命名空间的定义以及注意事项
	标准C++引入关键字namespace(命名空间/名字空间/名称空间),可以更好地
控制标识符的作用域。
#include<iostream>
using namespace std;

//命名空间

//注: 1.命名空间只能定义为全局的,不能定义为局部的
namespace A//A是命名空间的名字
{
	int a;
	void b()
	{
	}
}

//	   2.命名空间可以嵌套命名空间
namespace M
{
	namespace B
	{
		int a = 112;
		void b()
		{

		}
	}
}

//	    3.命名空间是开放的,随时可以加入新成员,但是新成员只能在加入后使用
namespace M
{
	int c = 10;
	//此时,M命名空间中有三个元素,a,b(),c ;
}

int temp = 10;

//		 4.命名空间取别名,可以通过新名字访问旧名字中的属性等
void test01()
{
	//		  新名字	旧名字
	namespace nameNew = M;
	cout << "nameNew::B::a = " << nameNew::B::a << endl;

}

//		  5. 分文件编写代码时,如果.h中有两个命名空间,但是里面的成员函数重名的时候,在.cpp中实现这个函数要加上作用域命名空间
//			 但是如果在.h中的命名空间中定义一个变量的话,会导致出现重定义的作用,是因为引入.h文件的时候,相当于将.h文件中的内容拿到主函数中,此时.h和.c文件中都会存在这个变量,就会导致重定义
//			 但是为什么命名空间中有函数不会报错呢,是因为函数在.h中起到的是声明的作用,因此就在.c中引入头文件的时候就不会报错
int main()
{
	int temp = 20;
	cout << "temp = " << temp << endl;
	cout << "::temp = " << ::temp << endl;
	cout << "M::c = " << M::c << endl;
	cout << "M::B::a = " << M::B::a << endl;
	
	system("pause");
	return 0;
}
2.2 using声明和编译指令
	当仅仅只是使用某一命名空间中的变量的时候,该变量可以理解为在当前函数体内部
定义了一个局部变量,大小与名字都与命名空间中的相同,因此此时,就不能对该变量
进行初始化等操作了;
	当将整个命名空间都y引入的时候,相当于对于当前函数体来讲,他们有一个装着全
局变量和全局函数的空间供他们使用,此时不论是重定义还是直接使用这些变量都是可
以的。
#include<iostream>
using namespace std;

namespace A
{
	int a = 10;
	int b = 20;
	int c = 30;
}

void test01()
{
	//访问A命名空间下的a的两种方式
	
	//cout << A::a << endl;
	using A::a;
	cout << a << endl;

	//int a = 100;//error,因为上述代码使用using后,就相当于重新在该函数内部定义a(此时a就可以理解为局部变量),因此不可以重复定义,但是可以多次赋值
	a = 100;
	cout << a << endl;
}

void test02()
{
	//在当前函数的作用域(该函数执行结束后自动销毁)下,都可以使用命名空间A中的变量或者函数
	using namespace A;
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	//以下代码不会报错,是因为A命名空间中定义的a是全局变量,而下面定义的a是局部变量,因此不会报错
	int a = 1000;
	int b = 2000;
	int c = 3000;
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;

}

int main()
{
	//test01();
	test02();
	system("pause");
	return 0;
}

3.C++与C区别

3.1 结构体
	1.在C语言中,使用自定义的结构体时,必须要加struct关键字进行修饰,而在C++中
可以不加struct。
	2.在C语言中,机构体的定义中不可以使用函数,而在C++的结构体的定义中可以
定义函数。
#include<iostream>
using namespace std;

struct Person
{
	char name[64];
	int age;
	void func()
	{
		cout << "helloworld" << endl;
	}
};

void test01()
{
	//在cpp中,自定义的结构类型在使用的时候是不需要加struct关键字的
	Person p1;
	//在cpp中,自定义的数据类型中可以写函数
	p1.func();
}

int main()
{
	test01();
	system("pause");
	return 0;
}
3.2 类型转换
	在C语言中,例如在堆空间中开辟内存的时候,编译器会默认执行隐式转换将类
型转换,但是在C++中则必须进行类型强转才行,否则会报错:
void test01()
{
	//char*p = malloc(sizeof(char)*64);//error
	char* p = (char* )malloc(sizeof(char)*64);
}
3.3 三目运算符的使用区别
	在C语言中,返回的是值,是变量所代表的值,但是在C++中返回的是地址。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

void test()
{
	int a = 10;
	int b = 20;
	printf("%d\n", a > b ? a : b);
	//(a > b ? a : b) = 100;err
	//这个表达式返回的是右值,是数值,返回的是20
	//20 = 100;
	*(a > b ? &a : &b) = 100;
	printf("b=%d\n", b);
}

int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}


3.4 const修饰变量
	在C语言中,定义全局const变量,会将变量存储到常量区;但是在C++中,定义
全局const变量,不会给变量分配内存;在C++中,const修饰的全局变量具有内部
链接属性,即只能在当前文件中访问,不能在整个项目访问。
	在C++中,一般都不会给const修饰的变量分配内存,但是当编译阶段计算机检查
到函数体内部有使用到const修饰的那个变量进行了取地址操作,或者是将这个变量
定义为extern的时候,此时就会给const所对应的空间分配内存。分配内存后,存储
位置也都为常量区,因此也不可以修改。
	在定义数据的时候,假如用到define关键字,则最好将define关键字对应的值转换
为const类型进行定义,因此define关键字不会指出函数的数据类型,因此在之后进
行函数重载的时候,可能就会出现无法达到预期的效果。

	c++中对于局部的const变量要区别对待:
	1.对于基础数据类型,也就是const int a = 10这种,编译器会进行优化,将值(10)替
换到访问的位置。	
	2.对于自定数据类型,比如类对象,那么也会分配内存,此时修改可以通过指针
间接修改。
#include<iostream>
using namespace std;

const int a = 10;

void test01()
{
	//在C++中的编译阶段,会变为 cout<<"const int a = "<<10<<endl;
	cout << "const int a = " << a << endl;

	const int b = 20;
	int* p = (int *)&b;
	*p = 200;
	//在编译器编译的时候,会运行 cout << "b = "<<20<<endl;
	//因此会出现通过C语言的写法改变值的方法不正确
	cout << "b = " << b << endl;
	cout << "*p = " << *p << endl;

	cout << "b 的地址为:" << &b << endl;
	cout << "p指向的地址为:" << p << endl;

	//如果想通过指针的办法修改值,可使用关键字volatile,可以禁止编译器优化
	volatile const int c = 30;
	int* p1 = (int*)&c;
	*p1 = 300;
	cout << "c = " << c << endl;
	cout << "*p = " << *p << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

4.引用

4.1 引用的定义
	引用是c++对c的重要扩充。在c/c++中指针的作用基本都是一样的,但是c++增加
了另外一种给函数传递地址的途径,这就是按引用传递
	同指针相比,引用的写法能更加简便点,从功能上来看,二者基本上拥有相同的功
能,引用就是对一个已定义变量的起别名。

	基本语法: 
					Type& ref = val;
	注意事项:
	&在此不是求地址运算,而是起标识作用。
	类型标识符是指目标变量的类型
	必须在声明引用变量时进行初始化。
	引用初始化之后不能改变。
	不能有NULL引用。必须确保引用是和一块合法的存储单元关联。
	建立对数组的引用。
#include<iostream>
using namespace std;

//引用的写法
void test01()
{
	int a = 10;
	int& b = a;//引用起别名

	b = 100;
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;

	//使用指针的写法
	int a1 = 10;
	int* b1 = &a1;
	*b1 = 100;

	cout << "a1 = " << a1 << endl;
	cout << "*b1 = " << *b1 << endl;
}

//引用的用法,等价于地址传递
void func(int& a)
{
	a = 111;
}

void test02()
{
	int a = 10;
	func(a);
	cout << "func作用后:a = " << a << endl;
}

int main()
{
	test01();
	//test02();
	system("pause");
	return 0;
}
4.2 引用的注意事项
	1.引用创建时,必须进行初始化
	2.引用一旦初始化不能改变他的指向,只能修改它所指向的那片内存空间中的值。
	3.引用必须指向的是一片合法的空间
#include<iostream>
using namespace std;

void test01()
{
	//1.引用创建时,必须进行初始化
	//int& b;//error
	
	//2.引用一旦初始化不能改变他的指向
	int a = 10;
	int b = 20;
	int& a1 = a;
	a1 = b;//赋值操作,即将b的值赋值给a1所指向的那片空间
	cout << " a = " << a << endl;
	cout << " b = " << b << endl;
	cout << "a1 = " << a1 << endl;

	//3.引用必须指向的是一片合法的空间
}

int main()
{
	test01();
	system("pause");
	return 0;
}
4.3 引用的本质
	引用的本质在c++内部实现是一个常指针:
				Type& ref = val; // Type* const ref = &val;
	因此,在对引用进行创建的时候,必须要对他进行初始化。
//发现是引用,转换为 int* const ref = &a;
void testFunc(int& ref){
	ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
	int a = 10;
	int& aRef = a; //自动转换为int* const aRef = &a;这也能说明引用为什么必须初始化
	aRef = 20; //内部发现aRef是引用,自动帮我们转换为: *aRef = 20;
	cout << "a:" << a << endl;
	cout << "aRef:" << aRef << endl;
	testFunc(a);
	return EXIT_SUCCESS;
}
4.4 数组的引用
	数组的引用在定义的时候,与数组指针的定义方式十分相似,因此二者可以进行比较
记忆。
#include<iostream>
using namespace std;

void test01()
{
	int arr[5] = { 1,2,3,4,5 };
	int len = sizeof(arr) / sizeof(arr[0]);
	//1.第一种定义方法
	typedef int(MYARR1)[5];
	MYARR1& arr1 = arr;

	//2.第二种定义方法
	typedef int(&MYARR2)[5];
	MYARR2 arr2 = arr;

	//3.第三种定义方式
	int(&arr3)[5] = arr;

	for (int i = 0; i < len; i++)
	{
		cout << arr3[i] << " ";
		cout << arr1[i] << " ";
		cout << arr2[i] << " ";
		cout << endl;
	}
}

int main()
{
	test01();
	system("pause");
	return 0;
}
4.5 指针的引用
	在C语言中,我们进行传参的时候,假如被调函数需要传递的参数是一个二级指针,
那么我们可能需要很多操作,创建一级指针或者是取到我们在主调函数中所创建的要
传入的变量的地址,将其传入被调函数中,但是通过引用的方式,可以简便很多写法,
因为从本质上来看,引用作用与指针是类似的,对一级指针取引用,本质上和一级指
针的指针的功能是类似的,因此在这个时候,我们就可以简化很多写法。
#define _crt_secure_no_warnings
#include<iostream>
using namespace std;

void test01()
{
	指针的引用是给指针变量这片空间起别名
	 const char* p = "石头";
	 const char* &p1 = p;

	 cout << p << endl;
	 cout << p1 << endl;
}

void func(char* &temp)
{
	char* p = (char* )malloc(sizeof(char)* 64);
	memset(p, 0, 64);
	strcpy(p, "石头");

	temp = p;
}

void test02()
{
	char* p = null;
	func(p);
	cout << p << endl;
}

int main()
{
	test02();
	system("pause");
	return 0;
}
4.6 常量引用
	常量引用注意:
		1.字面量不能赋给引用,但是可以赋给const引用
		2.const修饰的引用,不能修改。
void test01(){
	int a = 100;
	const int& aRef = a; //此时aRef就是a
	//aRef = 200; 不能通过aRef的值
	a = 100; //OK
	cout << "a:" << a << endl;
	cout << "aRef:" << aRef << endl;
}
void test02(){
	//不能把一个字面量赋给引用
	//int& ref = 100;
	//但是可以把一个字面量赋给常引用
	const int& ref = 100; //int temp = 200; const int& ret = temp;
}
4.7 引用的使用
	常量引用主要用在函数的形参,尤其是类的拷贝/复制构造函数。
	将函数的形参定义为常量引用的好处:
	1.引用不产生新的变量,减少形参与实参传递时的开销。
	2.由于引用可能导致实参随形参改变而改变,将其定义为常量引用可以消除这种
副作用;如果希望实参随着形参的改变而改变,那么使用一般的引用,如果不希望
实参随着形参改变,那么使用常引用。

注:
	最常见看见引用的地方是在函数参数和返回值中。当引用被用作函数参数的时,
在函数内对任何引用的修改,将对还函数外的参数产生改变。当然,可以通过传递
一个指针来做相同的事情,但引用具有更清晰的语法。
	如果从函数中返回一个引用,必须像从函数中返回一个指针一样对待。当函数返
回值时,引用关联的内存一定要存在。
	1.不能返回局部变量的引用
	2.如果函数做左值,那么必须返回引用
//值传递
void ValueSwap(int m,int n){
	int temp = m;
	m = n;
	n = temp;
}
//地址传递
void PointerSwap(int* m,int* n){
	int temp = *m;
	*m = *n;
	*n = temp;
}
//引用传递
void ReferenceSwap(int& m,int& n){
	int temp = m;
	m = n;
	n = temp;
}
void test(){
	int a = 10;
	int b = 20;
	//值传递
	ValueSwap(a, b);
	cout << "a:" << a << " b:" << b << endl;
	//地址传递
	PointerSwap(&a, &b);
	cout << "a:" << a << " b:" << b << endl;
	//引用传递
	ReferenceSwap(a, b);
	cout << "a:" << a << " b:" << b << endl;
}

//返回局部变量引用
int& TestFun01(){
	int a = 10; //局部变量
	return a;
}
//返回静态变量引用
int& TestFunc02(){	
	static int a = 20;
	cout << "static int a : " << a << endl;
	return a;
}
int main(){
	//不能返回局部变量的引用
	int& ret01 = TestFun01();
	//如果函数做左值,那么必须返回引用
	test();
	TestFunc02();
	TestFunc02() = 100;
	TestFunc02();

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值