C++与C的区别一(学习笔记)

本文详细介绍了C++中的头文件区别、标准输入输出库的使用、命名空间的创建与访问规则,包括不嵌套和嵌套访问,以及usingnamespace的简单应用和作用域问题。此外,还讨论了函数重载、左值引用、auto和decltype的用法。
摘要由CSDN通过智能技术生成

头文件区别

  • c++标准库中所有的头文件包含方式采取无.h后缀的方式包含如:#include< iostream >
  • 在c++文件中包含c标准库的头文件有两种方式
    • 有后缀.h
      • 如: #include< stdio.h >,#include< stdlib.h >
    • 无后缀
      • 如:#include< cstdio >,#include< cstdlib >
  • c++和c的头文件扩展名不同(这里的头文件指自己写的头文件)
    • c的扩展名是.h
    • c++的扩展名是.hpp

注意:c++兼容c语言所以在c++文件中,自己写的头文件可以是.h为后缀,也可以是.hpp为后缀

标准库i/o区别

  • C输入输出需要包含#include< stdio.h >,C++输入输出需要包含#include< iostream >

命名空间的创建

namespace MM
{
 	int age;
  	void print()
  	{
      	printf("我在MM里面\n");
  	}
  	struct Info
  	{
     	char*name;
     	int num;
  	};
}

这是第一种写法,可以将函数和结构体定义在命名空间内部
让我们来看看第二种写法

namespace GG
{
	int age;
	//声明函数
  	void print();
  	//声明结构体
  	struct Info;
}
//在命名空间外实现
void GG::print()
{
	printf("我在GG外面实现的\n");
}
struct GG::Info
{
     char*name;
     int num;
};

可以看见在名空间内部实现函数和结构体的方式有两种

  1. 直接将函数和结构体定义在命名空间内部
  2. 先在命名空间内部声明再在外部定义

命名空间的好处

  1. 可以提高标识符的使用率(翻译过来就是可以使用相同的变量名)
  2. 避免命名污染

命名空间的访问

不嵌套访问
namespace MM
{
 	int age;
  	void print()
  	{
      	printf("我在MM里面\n");
  	}
  	struct Info
  	{
     	char*name;
     	int num;
  	};
}
int main()
{
	MM::age=1;
	MM::print()
	MM::Info a={"张三"3}; //注意在C++中结构体定义变量用结构体名也可以
	struct MM::Info b={"李四"4};  //加上struct 定义变量也可以
	return 0;
}

嵌套访问
namespace A
{
	int a;
	namespace B
	{
		int b;
		namespace C
		{
			int c;
		}
	}
}
int main()
{
	//访问A里面的a
	A::a;
	//访问A里面的B里面的b
	A::B::b;
	//访问A里面的B里面的C里面的c
	A::B::C::c;
	return 0;
}
用using namespace实现简单嵌套访问
#include<stdio.h>
namespace A
{
	int a=1;
	namespace B
	{
		int b=2;
		namespace C
		{
			int c=3;
		}
	}
}
int main()
{
	
	//去掉前缀访问A里面的a
	using namespace A;
	printf("a=%d\n",a);
	//去掉前缀访问A里面的B里面的b
	using namespace A::B;
	printf("b=%d\n",b);
	//去掉前缀访问A里面的B里面的C里面的c
	using namespace A::B::C;
	printf("c=%d\n",c);
	//访问a,b,c
	printf("a=%d,b=%d,c=%d\n",a,b,c);
	return 0;
}
输出结果
a=1
b=2
c=3
a=1,b=2,c=3

using namespace 作用域问题

#include<stdio.h>
using namespace Q
{
	int a=1;
	int b=2;
}
void test_usingnamespace()
{
	using namespace Q;
	printf("a=%d\n",a);
	printf("a=%d\n",b);
}
int main()
{
	test_usingnamespace();
	//此时我在这里去掉前缀访问
	a=2//注意这是错误的写法,因为此时using namespace Q 的作用域管不到这里,只在test_usingnamespace()函数中起作用
	//此时正确写法应该是如下
	Q::a=2;
	printf("a=%d\n",Q::a); 
	
	return 0;
}

输出结果
a=1
b=2
a=2

::(作用域分辨符的作用)

#include<stdio.h>

int a=3;

int main()
{
	int a=1;
	printf("a=%d\n",a); //当全局变量和局部变量同名时根据就近原则,取a=1
	printf("a=%d\n",::a); //如果在a前面加上::(作用域分辨符)则取全局变量a=3;
	return 0;
}

输出结果
a=1
a=3

注意::: (作用域分辨符)只在C++中有效C源文件中没有,这个是C++针对这种情况做出的优化

"using ::函数名"的作用

#include<stdio.h>
//第一种写法
void printData()
{
	printf("%d\n", 3);
}

namespace G
{
	void printData()
	{
		//函数根据就近原则调用,此时形成死递归
		printData();
	}
}

int main()
{
	
	G::printData();
	return 0;
}
编译结果
warning C4717: “G::printData”: 如递归所有控件路径,函数将导致运行时堆栈溢出
//第二种写法
void printData()
{
	printf("%d\n", 3);
}

namespace G
{
	void printData()
	{
		using::printData;  //声明下面函数的来源于全局,下面函数将调用全局函数
		printData();
	}
}

int main()
{
	
	G::printData();
	return 0;
}
输出结果
3

using 替换typedef的功能

int main()
{
	typedef int INT;  //将int取别名为INT
	INT a=1;  //这里其实是 int a=1;
	
	using INT=int; //这里也是取别名,将int 取别名为INT
	INT b=2;   //这里其实是 int b=2;
	return 0;
}

这个using 取别名标识符=被取别名标识符,是C++里面的功能,与typedef 被取别名标识符 取别名标识符 有着相同的功能,如果非要我来评价一下哪个更好理解,我觉得C++的应该更好理解,如using INT = int 可以理解为int 类型赋值给INT,让INT拥有int 类型。

函数重载

参数数量不同
#include<stdio.h>

void test(int a,int b)
{
	printf("我有两个参数\n");
}
void test(int a)
{
 	printf("我只有一个参数\n");
}

int main()
{
	test(1);
	test(1,2);
	return 0;
}
输出结果
我只有一个参数
我有两个参数
参数类型不同
void test(int a)
{
	printf("我是整型\n");
}
void test(double a)
{
 	printf("我是双精度浮点型\n");
}

int main()
{
	test(1);
	test(1.2);
	return 0;
}
参数顺序不同

错误展示×

#include<stdio.h>

void test(int a,int b)
{
	printf("我们顺序不同\n");
}
void test(int b,int a)
{
 	printf("我们顺序不同\n");
}

int main()
{
	test(1);
	test(1,2);
	return 0;
}

注意:上面这种写法是错误的,程序不会去看你的形参,而是去看你的参数的类型,我们不看形参,只看类型,可以看出来这两个函数是一模一样的,不满足函数重载的条件,像test(int a,int b)参数类型一样则不满足参数顺序交换的条件,函数参数类型不同时,才满足参数顺序交换

正确展示√

#include<stdio.h>

void test(int a,double b)
{
	printf("我们两个函数参数类型顺序不同,且函数中两个参数类型不同\n");
}
void test(double b,int a)
{
 	printf("我们两个函数参数类型顺序不同,且函数中两个参数类型不同\n");
}

int main()
{
	test(11.1);
	test(1.1,2);
	return 0;
}

函数参数中const小知识

#include<stdio.h>
void test_const(char*str) //此时参数没加const修饰,让我们看看效果吧
{
	printf("在C++中在传字符串时是比较严格的\n");
}
int main()
{
	test_const("我进来啦")
	return 0;
}

让我们来看看编译结果吧

编译结果
error C2664:void test_const(char *): 无法将参数 1 从“const char [9]”转换为“char *

很明显编译都无法通过,那么接下来让我们来看看能否传字符串变量进去

#include<stdio.h>
void test_const(char*str) //此时参数没加const修饰,让我们看看效果吧
{
	printf("在C++中在传字符串时是比较严格的\n");
}
int main()
{
	char arr[]="我来试试";
	test_const(arr);
	return 0;
}
输出结果
在C++中在传字符串时是比较严格的

从上面的输出结果可以看出函数参数在没有用cosnt 来修饰的时候是可以传字符串变量的,那么怎么才能既可以传字符串常量,又可以传字符串变量呢?接下来让我们来看看const 修饰char*的作用吧!!!

测试一、现在传的是字符串常量

#include<stdio.h>
void test_const(const char*str) 
{
	printf("加了const修饰char*既可以传字符串常量,又可以传字符串变量\n");
}
int main()
{
	test_const("我进来啦") //此时是字符串常量
	return 0;
}
输出的结果
加了const修饰char*既可以传字符串常量,又可以传字符串变量

测试二、现在传的是字符串变量

#include<stdio.h>
void test_const(const char*str) 
{
	printf("加了const修饰char*既可以传字符串常量,又可以传字符串变量\n");
}
int main()
{
	char arr[]="我来试试";
	test_const(arr);
	return 0;
}
输出的结果
加了const修饰char*既可以传字符串常量,又可以传字符串变量

函数缺省

注意:
  1. 在写多文件时只能在头文件中写函数的缺省,不能在实现时写函数缺省
  2. 在写单文件时可以在函数实现时写函数缺省
  3. 在写函数缺省的时候只能依次从右向左缺省

让我们来看看写单文件时的函数缺省写法

#include<stdio.h>
void test(int a=1,int b=2,int c=3)
{
	printf("a=%d,b=%d,c=%d\n",a,b,c);
}
int main()
{
	test(100);
	test(100,200);
	test(100,200,300);
	return 0;
}
输出结果
a=100,b=2,c=3
a=100,b=200,c=3
a=100,b=200,c=300

让我们来看看注意点3的错误写法

#include<stdio.h>
void test(int a=1,int b,int c=3)
{
	printf("a=%d,b=%d,c=%d\n",a,b,c);
}
int main()
{
	test(100);
	return 0;
}

如果跳跃式缺省,在函数调用时,此时我传入了100,这100,程序不知道应该分配给谁了,它不会自动帮你分配给第二个参数b,这样缺省是不对的

新数据类型

bool类型的大小
#include<iostream>
using namespace std;
int main()
{
	bool flag=true;
	cout<<"字节大小:"<<sizeof(flag)<<"\n";
	return 0;
}
输出结果
字节大小:1
左值引用

什么是左值引用呢?顾名思义就是等号左边的标识符称为左值,左值引用的表示方法为:类型& 标识符=左值,就是给一段相同的内存取一个别名,可能大家现在还是一头雾水,接下来我们一起看看左值引用是如何应用的吧,请看代码

第一种用法:

#include<iostream>
using namespace std;
int main()
{
	int a=3;
	int& b=a; //这一条语句的意思是给a取了一个别名为b
	b=30;      //改变b就是改变a,因为b就是a ,它们是共用的同一段内存
	cout<<"a="<<a<<"\n";
	cout<<"b="<<b<<"\n";
	return 0;
}
输出结果
a=30
b=30

第二种用法

#include<iostream>
using namespace std;
void test1(int*p)
{
	*p=30;
}
void test2(int&b)
{
	b=300; 
}
int main()
{
	int a=3;
	/*test1和test2都是为了改变外部变量a的值,只是方式各不同,
	test1是通过传地址改变a的值,test2是通过左值引用的方法改变a的值无须传地址*/
	test1(&a);
	cout<<"a="<<a<<"\n"; 
	test2(a);
	cout<<"a="<<a<<"\n"; 
	return 0;
}
test1输出的结果
a=30
test2输出的结果
a=300
auto和decltype的用法

auto和decltype两者搭配使用,auto用来推断类型,decltype可以使用auto推断出的类型创建变量,话不多说,我们来看代码

#include<iostream>
using namespace std;
int main()
{
	
	auto b = 3;  //此时auto 将b推断成int类型
	decltype(b) w = 10;  /* decltype(b)->int w=10; decltype()可以拿着auto推断出来的类型
	 创建相应类型的变量 */
	cout << w;
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值