C++初阶

目录

前言

1、命名空间

2、缺省参数

3、函数重载

4、引用

5、宏

6、内联函数


前言

.c文件调用的是c语言的编译器 .cpp文件调用的是c++的编译器,根据后缀调用编译器

        

#include<stdio.h>
int rand = 0;
int main()
{
	printf("hello world\n");
	printf("%d\n", rand);
}

#include<stdio.h>
#include<stdlib.h>
//命名冲突
int rand = 0;
int main()
{
	printf("hello world\n");
	printf("%d\n", rand);
}

 

c语言中不同项目中有相同的命名,合并后会发生冲突,因此c++使用命名空间来解决这一问题

1、命名空间

#include<stdio.h>
#include<stdlib.h>
namespace test
{
	int rand = 0;
}

int main()
{
	printf("hello world\n");
	printf("%p\n", rand);//默认会在全局中寻找,不会进入命名空间

	//域作用限定符::
	printf("%p\n", test::rand);
	return 0;
}

namespace test
{
	// 命名空间中可以定义变量/函数/类型
	int rand = 10;

	int Add(int left, int right)
	{
		return left + right;
	}

	struct Node
	{
		struct Node* next;
		int val;
	};
}
int main()
{
	printf("%d\n", test::rand);
	printf("%d\n", Add(1, 2));//×
    printf("%d\n", test::Add(1, 2));//√
    struct test::Node node;//命名空间中结构体的使用方法
	return 0;
}

1.1默认情况下,直接使用Add函数是在全局范围内寻找,不会在命名空间内寻找,这样是找不到的,需要使用域作用限定符 :: 指定命名空间test使用Add函数

#include<stdio.h>
#include<stdlib.h>
namespace test
{
	// 命名空间中可以定义变量/函数/类型
	int rand = 10;

	int Add(int left, int right)
	{
		return left + right;
	}

	struct Node
	{
		struct Node* next;
		int val;
	};
}

using namespace test;//全部展开(授权)命名空间,相当于命名空间已经失效,可任意访问

int main()
{
	printf("%d\n", test::Add(1, 2));
	printf("%d\n", Add(1, 2));//Add可以任意使用,可以不用域作用限定符
	printf("%d\n", test::rand);
	printf("%d\n", rand);//×这里的的rand不明确,无法确定是stdlib.h库中的rand还是展开的命名空间中的rand

	return 0;
}
namespace test
{
	// 命名空间中可以定义变量/函数/类型
	int rand = 10;

	int Add(int left, int right)
	{
		return left + right;
	}

	struct Node
	{
		struct Node* next;
		int val;
	};
}

using test::Add;//部分展开(授权)命名空间
int main()
{

	printf("%d\n", test::rand);
    //频繁调用Add函数时,可将命名空间中的Add部分展开以便调用
	printf("%d\n", Add(1, 2));
	printf("%d\n", Add(2, 3));
	printf("%d\n", Add(3, 4));
	printf("%d\n", Add(4, 5));
	printf("%d\n", Add(5, 6));
	printf("%d\n", Add(6, 7));
    struct test::Node node;
    return 0;
}

 1.2命名空间可以嵌套

#include<stdio.h>
#include<stdlib.h>
namespace test
{
	int rand = 0;
	namespace test1
	{
		int rand = 1;
	}
}
int main()
{
	printf("%p\n", rand);
	printf("%d\n", test::rand);
	printf("%d\n", test::test1::rand);//命名空间的嵌套
	return 0;

}

 

#include<iostream>
//头文件的展开是把头文件的内容拷贝过来

using namespace std;
//std是c++标准库的命名空间
//std命名空间的全展开,是一种授权
int main()
{
	cout << "hello world" << endl;
	cout << "hello world" << endl;
	cout << "hello world" << endl;
	int i = 0;
	std::cin >> i;
	return 0;
}
#include<iostream>

//std命名空间的部分展开
using std::cout;
using std::cin;
using std::endl;
int main()
{
	cout << "hello world" << endl;
	cout << "hello world" << endl;
	cout << "hello world" << endl;
	int i = 0;
	std::cin >> i;
	return 0;
}

1.3多个文件中的相同名字的命名空间会自动合并

2、缺省参数

缺省参数是 声明或定义函数时 为函数的 参数指定一个缺省值 。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

2.1全缺省

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
void Func(int a = 10, int b = 20, int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;

}
int main()
{
	Func();
	Func(1);//默认传给第一个形参
	Func(1,2);
	Func(1,2,3);
    //显示传参,从左往右显示传参
    Func(,,1)//×这种传参是不允许的
	return 0;

}

2.2半缺省(必须从右往左给缺省值)


#include<iostream>
using std::cout;
using std::cin;
using std::endl;
void Func(int a, int b = 20 , int c = 30)
{
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl << endl;

}
int main()
{
    Func();//×
	Func(1);//至少要传一个参数(根据半缺省部分的个数来确定至少传几个参数)
	Func(1,2);
	Func(1,2,3);
	return 0;

}

2.3缺省参数的应用

//Stack.h
namespace test
{
	typedef struct Stack
	{
		int* a;
		int top;
		int capacity;
	}ST;
	void StackInit(ST* ps, int N = 4)
	{
		ps->a = (int*)malloc(sizeof(int) * N);
		ps->top = 0;
		ps->capacity = 0;
	}
	void StackPush(ST* ps, int i)
	{

	}

}
int main()
{
	test::ST st1;
	StackInit(&st1,10);
	for (size_t i = 0; i < 10 ; i++)
	{
		StackPush(&st1, i);
	}
	test::ST st2;
	StackInit(&st2, 100);
	for (size_t i = 0; i < 100; i++)
	{
		StackPush(&st2, i);
	}
	test::ST st3;
	StackInit(&st3);//不知道可能会插入几个,缺省参数
	return 0;
}

 注:不允许函数的声明(.h)和定义(.cpp)同时给缺省参数,规定声明给参数,定义不给参数,(因为包含头文件(.h),使用头文件中的缺省值)

3、函数重载

函数重载: 是函数的一种特殊情况, C++ 允许在 同一作用域中 声明几个功能类似的 同名函数 ,这些同名函数的形参列表 ( 参数个数 或 类型 或 类型顺序 ) 不同 ,常用来处理实现功能类似数据类型不同的问题。

#include<iostream>
using std::cout;
using std::cin;
using std::endl;
//参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
// 2、参数个数不同
void f()
{
    cout << "f()" << endl;
}
void f(int a)
{
    cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
    cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
    cout << "f(char b, int a)" << endl;
}
int main()
{
    cout << Add(10, 20) << endl;
    cout<<Add(10.1, 20.2)<<endl;
    f();
    f(10);
    f(10, 'a');
    f('a', 10);
    return 0;
}

注:单纯函数的返回值不同不能构成重载

namespace bit1
{
	void func(int x)
	{}
}

namespace bit2
{
	void func(double x)
	{}
}
//不构成函数重载,原因是两个函数的作用域不同,函数重载要求在同一作用域中
------------------------------------------------------------------
namespace bit1
{
	void func(int x)
	{}
}

namespace bit1
{
	void func(double x)
	{}
}
//构成函数重载,因为两个命名空间会合并
void func(int a)
{
	cout << "void func(int a)" << endl;
}

void func(int a, int b = 1)
{
	cout << "void func(int a, int b)" << endl;
}

//构成函数重载,因为参数的个数不同
int main()
{
	func(1, 2);
	//会调用第二个函数
	func(1);
    //调用存在歧义,第二个是半缺省,不知道调用哪个
	return 0;
}

4、引用

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
int main()
{
    int a = 0;
	int& b = a; // 引用
    cout << &a << endl;
	cout << &b << endl;
	a++;
	b++;
	return 0;
}

4.1引用的特性:

1. 引用在 定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用
引用返回,如果已经还给系统了,则必须使用传值返回。
4.2常引用
// 在引用的过程中
// 权限可以平移
// 权限可以缩小
// 权限不能放大

int main()
{

    const int a = 0;
    int& b = a;//×权限的放大,这是错误的

    const int& c = a;//√权限的平移

	int x = 0;
	const int& y = x;//√权限的缩小
    
    int i = 0;
    double& d = i;//×类型转换时会产生临时变量,临时变量具有常性,这种引用时一种权限的放大
    const double& d = i;//√
	return 0;
}
int func()
{
	int a = 0;
	return a;
}
int main()
{
	int& ret = func();//×这里返回给ret的不是a,是a的拷贝,是一种临时变量,具有常性,这是一种权限的放大
    const int& ret = func();//√
	return 0;
}
4.3引用和指针的区别
#include<iostream>
using namespace std;
int main()
{
	int a = 0;
	int* p1 = &a;
	int& ref = a;
	return 0;
}

在语法概念上引用就是一个别名,没有独立的空间和其引用的实体公用同一块空间;

转到汇编代码发现在底层实现上引用实际是有空间的,引用的实现方式与指针是相同的

引用和指针的不同点 :
1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用 在定义时 必须初始化 ,指针没有要求
3. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任何一个同类型实体
4. 没有 NULL 引用 ,但有 NULL 指针
5. sizeof 中含义不同 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32位平台下占4 个字节 )
6. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全

5、宏

注:宏是一种替换

几种错误的宏函数定义方法

#include<stdio.h>
#define ADD(x,y) x+y;//1
int main()
{
	printf("%d\n", ADD(1, 2));//等价于打印 3;是有问题的,所以不能加宏函数末尾不加;
	return 0;
}
#include<stdio.h>
#define ADD(x,y) x+y//2
int main()
{
	printf("%d\n", ADD(1, 2)*3);//结果是1+2*3=7,而不是想要的9
	return 0;
}
#include<stdio.h>
#define ADD(x,y) (x+y);//3
int main()
{
	int a = 1 , b = 2;
	printf("%d\n", ADD(a | b, a & b));//由于+的优先级高于|和&所以会先计算b+a再计算&和|
	return 0;
}
#define ADD(x,y) ((x)+(y))//正确写法

宏函数的缺点:

1、容易出错,语法坑很多

2、不能调试

3、没有类型安全的检查

宏函数的优点:

1、没有类型的严格限制

2、针对频繁调用的小函数,不需要再建立栈帧,提高了效率

6、内联函数

inline 修饰 的函数叫做内联函数, 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数调
用建立栈帧的开销,内联函数提升程序运行的效率。
#include<stdio.h>
inline int add(int x, int y)
{
	return x + y;
}
int main()
{
	int ret = add(1, 2);
	printf("%d\n", ret);
	return 0;
}

 内联函数特性:

1. inline 是一种 以空间换时间 的做法,如果编译器将函数当成内联函数处理,在 编译阶段,会
用函数体替换函数调用 ,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。
2. inline 对于编译器而言只是一个建议,不同编译器关于 inline 实现机制可能不同 ,一般建
议:将 函数规模较小 ( 即函数不是很长,具体没有准确的说法,取决于编译器内部实现 )
是递归、且频繁调用 的函数采用 inline 修饰,否则编译器会忽略 inline 特性
3. inline 不建议声明和定义分离(指在两个文件中),分离会导致链接错误。因为 inline 被展开,不生成指令,就没有函数地址了,链接就会找不到
#include<stdio.h>
inline int add(int x, int y)
{
	return x + y;
}
inline int func()
{
	int x1 = 1;
	int x2 = 2;
	int x3 = 3;
	int x4 = 4;
	int ret = 0;
	ret += x1;
	ret -= x2;
	ret *= x3;
	ret /= x4;
	return ret;
}
int main()
{
	int ret = add(1, 2);
	printf("%d\n", ret);
	ret = func();
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值