【C++---1】入门(下)


名字修饰:

C语言中的函数名字修饰规则十分简单,简单到只是在名字前面添加了下划线,所以就没办法支持函数重载,因为在编译的时候函数名会冲突

具体报错:errorLNK2019:无法解析的外部符号_XXX(函数名),该符号在_main中被引用

在C++中,VS编译器下,H指的是int,N指的是double

int Add(int left,int right);

double Add(double left,double right);

int main()
{
		Add(1,2);
		Add(1.0,2.0);

		return 0;
}

对上述代码编译链接会产生如下错误:

errorLNK2019:无法解析的外部符号"double cdecl Add(double,double)"(?Add@@YANNN@Z)

errorLNK2019:无法解析的外部符号"int__cdecl Add(int,int)"(?Add@@YAHHH@Z)

VS中C++把函数返回值写入修饰名,其他编译器不一定


extern “c”:

有些时候C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “c”,意思是告诉编译器将该函数按照C语言规则来编译


引用:

引用不是新定义一个变量,只是给已存在的变量取了一个别名,两者代表的是同一个,概念上和引用的变量共用一块内存空间

类型& 引用变量名=引用实体;

void TestRef()
{
		int a=10;
		int& ra=a;

		printf("%p\n",&a);
		printf("%p\n",&ra);

得到的结果是两者的地址是一模一样的

引用的类型必须和实体是同种类型!

引用在定义时必须进行初始化!

常引用:

const int& b=10;

引用空间名字和地址未知----->临时空间具有常性

引用的使用场景:

1.做参数

void swap(int& left, int& right)
{
		int tmp = left;
		left = right;
		right = tmp;
}

2.做返回值

返回值的生命周期必须不受函数控制(返回值应该用全局变量/static类型变量接收)

int& Add(int a, int b)
{
	int c = a + b;
	return c;
}

int main()
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << ret << endl;

	system("pause");
	return 0;
}

Add(1,2)调用结束,栈上的空间还在,数据被下一次的Add调用覆盖掉,返回的ret变成了7

在这里插入图片描述
在这里插入图片描述

3.结构体成员访问设置别名

Struct A
{
		int age;
		int number;
};

int main()
{
		A aa;
		aa.age=10;
		int& b=aa,age;
		b=20;
}

传值和传引用的效率比较:

#include <time.h> 

struct A 
{    
	int a[10000]; 
};


void TestFunc1(A a) 
{}

void TestFunc2(A& a) 
{}

void TestRefAndValue() 
{
		A a;
		
		// 以值作为函数参数    
		size_t begin1 = clock();    
		
		for (size_t i = 0; i < 10000; ++i)
		{
			TestFunc1(a);
		}
		
		size_t end1 = clock();
	
		// 以引用作为函数参数    
		size_t begin2 = clock(); 
		  
		for (size_t i = 0; i < 10000; ++i)
		{
			TestFunc2(a);
		}
		
		size_t end2 = clock();
	
		// 分别计算两个函数运行结束后的时间    
		cout << "TestFunc1(int*)-time:" << end1 - begin1 << endl;    
		cout << "TestFunc2(int&)-time:" << end2 - begin2 << endl; 
}

// 运行多次,检测值和引用在传参方面的效率区别 
int main() 
{    
		for (int i = 0; i < 10; ++i)    
		{        
			TestRefAndValue();    
		}  

		system("pause");
		return 0; 
}

在这里插入图片描述
传值的效率要比传引用差很多
传指针的效率几乎和传引用一致

引用和指针的区别:

在概念上,引用是实体的一个别名,是没有独立的内存空间的,但是底层实现上实际是有空间的,因为引用是按照指针方式来实现的,空间存放的实际是引用的实体的地址

引用和指针的不同点:

<1>引用在定义的时候必须初始化,指针没有要求
<2>引用在初始化一个实体之后不可以引用其他实体,但是指针可以在任何时候指向一个同类型的实体
<3>没有NULL引用但是有NULL指针
<4>sizeof中引用的大小为实体类型的大小,而指针的话在32位平台下都是4个字节
<5>引用自增代表实体自增,但是指针自增代表指针向后偏移一个类型的大小
(连续空间的指针自增才有意义)
<6>有多级指针,没有多级引用
<7>指针需要显示解引用,但是引用编译器会自己处理

T&<==>T* const

const T&<==>const T* const


内联函数:

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,提升程序运行的效率

release版本会展开,debug版本需要设置才可以展开

如果内联函数中有循环/递归那么编译器优化时会忽略掉内联

inline只能在当前文件中应用


宏的优缺点和替换方法:

优点:

<1>需要改动时,一改全改
<2>提高性能

缺点:

<1>3.14写成’3.14’时报错不明显
<2>max宏函数多次替换,如果内部有自增运算会出现多次自增

C++中的const int =10;相当于宏替换


auto关键字:

使用auto定义变量时必须进行初始化,否则无法根据初始化表达式进行推演变量类型

用auto声明指针类型时,用auto和auto*没有区别,但是auto声明引用类型时必须带&

void TestAuto()
{
		auto a=1,b=2;
		auto c=3,d=4.0;
}

这段代码编译会失败,因为c和d的初始化表达式类型不同

注意:
<1>auto不能作为函数的参数
<2>auto不能直接用来声明数组


范围for的语法:

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误.因此C++11中 引入了基于范围的for循环.for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量, 第二部分则表示被迭代的范围

在这里插入图片描述

使用条件:

for循环迭代的范围必须是确定的

迭代的对象要实现++和==的操作


指针空值:

NULL实际是一个宏,#define NULL 0

void f(int) 
{    
		cout<<"f(int)"<<endl; 
}
 
void f(int*)
{   
		cout<<"f(int*)"<<endl;
}
 
int main()
{   
		  f(0);   
		  f(NULL);   
		  f((int*)NULL);    
		  return 0; 
} 

这个时候就遇到了麻烦

所以避免混淆,C++11提供了nullptr;代表一个指针空值常量

在使用nullptr表示指针空值时,不需要包含头文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值