C++学习-->基础

目录

一、命名空间

1、namespace

2、命名空间的使用

1)指定访问命名空间的变量

2)using 展开

二、C++的输入和输出

1、cout 输出

2、cin 输入

3、endl 

三、缺省参数

四、函数重载

五、引用

1、引用的概念和定义

2、引用的特性

3、const 引用

4、指针与引用的关系

六、inline

七、nullptr


一、命名空间

命名空间是为了防止出现一些函数和变量出现命名冲突的问题,比如:

#include<stdio.h>

#include<stdlib.h>

int rand = 0;

int main()
{
    printf("%d\n",rand);
    return 0;
}

这里运行程序会报错,因为 stdlib.h 库中包含有 rand() 函数,与定义的 rand 变量会冲突

为了避免出现类似这类情况的命名冲突,需要应用到 namespace 关键字去定义命名空间

1、namespace

  • 定义命名空间,需要在 namespace 关键字后面跟命名空间的名字(自己取的),再接上 { } 就可以,在命名空间中可以定义 变量 / 函数 / 类型 等
namespace myname
{
}
  • namespace 的本质是定义一个域,域与全局域独立,不同的域可以定义同名变量
namespace myname
{
    int a = 10;
}

namespace yourname
{
    int a = 10;
}
  •  C++中有全局域、局部域、命名空间域、类域;域影响的是编译时语法查找一个 函数 / 变量 / 类型 出处(声明或定义)的逻辑,所以有了域的隔离,就可以解决命名冲突的问题。局部域和全局域除了会影响编辑查找逻辑,还会影响生命周期,命名空间域和类域不影响生命周期
    //全局域
    int a = 10;
    
    //命名空间域
    namespace myname
    {
        int a = 10;
    }
    
    int main()
    {
        //局部域
        int a = 10;
        return 0
    }
    
    
  • namespace 只能定义在全局,但可以嵌套
    namespace myname
    {
        int a = 10;
        namespace yourname
        {
            int b = 20;
        }
    }
    
  • 多文件中的同名 namespace 会合并,不会冲突
    namespace myname
    {
        int a = 10;
    }
    
    namespace myname
    {
        int b = 20;
    }
  • C++标准库都放在义个叫 std 的命名空间中

2、命名空间的使用

命名空间可以通过  " :: "  符号来访问

1)指定访问命名空间的变量

#include<stdio.h>

#include<stdlib.h>

namespace myname
{
    int rand = 10;
}

int main()
{
    printf("%d\n",myname::rand);
    return 0;
}

这样,rand() 函数,与定义的 rand 变量就不会冲突

//全局域
int a = 10;

//命名空间域
namespace myname
{
    int a = 10;
}

int main()
{
    //局部域
    int a = 10;

    //访问全局域
    printf("%d\n",::a);
    //访问局部域
    printf("%d\n",a);
    //访问命名空间域
    printf("%d\n",myname::a);
    return 0
}

2)using 展开

  • using 关键字可以指定展开命名空间中某个成员
#include<stdio.h>

namespace myname
{
	int Add(int a, int b)
	{
		return 10 * (a + b);
	}

	int Sub(int a, int b)
	{
		return 10 * (a - b);
	}
}

//指定展开命名空间某个成员
using myname::Add;

int main()
{
	printf("Add:%d\n", Add(10, 20));
	return 0;
}
  • using 关键字可以展开指定命名空间所有成员
#include<stdio.h>

namespace myname
{
	int Add(int a, int b)
	{
		return 10 * (a + b);
	}

	int Sub(int a, int b)
	{
		return 10 * (a - b);
	}
}

//展开指定命名空间所有成员
using namespace myname;

int main()
{
	printf("Add:%d\n", Add(20, 10));
	printf("Sub:%d\n", Sub(20, 10));
	return 0;
}

所以 using 还可以展开C++标准库

#include<iostream>
using namespace std;

二、C++的输入和输出

cout / cin / endl 都属于C++ 标准库,要通过命名空间的使用方式去使用

1、cout 输出

在C语言中," hello world " 的输出

#include<stdio.h>
int main()
{
	printf("hello world!!!");
	return 0;
}

而在C++中的输出

#include<iostream>
using namespace std;

int main()
{
	cout << "hello world!!!" ;
	return 0;
}
  • << 表示的是流插入运算符,与之相反的 >> 表示的是流提取运算符,即类似于河流的流向方向,<< 即流向输出,>> 即流向变量 
  • 与 printf 不同的是,cout 可以主动识别变量类型,不需要通过  " %d,%s,%c,%f,%lf "  等方式输出
#include<iostream>
using namespace std;//std命名空间包含所有的C++标准库

int main()
{
	int a = 10;
	double b = 0.1;
	char c = 'x';
	cout << "int:" << a << " \n ";
	cout << "double:" << b << "\n";
	cout << "char:" << c << "\n";
	return 0;
}

2、cin 输入

cin 与 scanf 类似,但不需要用到取地址符号 " & ",且与 cout 相同,不需要通过  " %d,%s,%c,%f,%lf "  等方式输入,可以自主地识别变量类型

#include<iostream>
using namespace std;//std命名空间包含所有的C++标准库

int main()
{
	int a = 10;
	double b = 0.1;
	char c = 'x';
	cout << "int:" << a << "\n";
	cout << "double:" << b << "\n";
	cout << "char:" << c << "\n";

	cin >> a >> b >> c;

	cout << "int:" << a << "\n";
	cout << "double:" << b << "\n";
	cout << "char:" << c << "\n";
	return 0;
}

3、endl 

endl 相当于 " \n " ,但不同的是 endl 是一个函数

#include<iostream>
using namespace std;//std命名空间包含所有的C++标准库

int main()
{
	int a = 10;
	double b = 0.1;
	char c = 'x';
	cout << "int:" << a << endl;
	cout << "double:" << b << endl;
	cout << "char:" << c << endl;

	cin >> a >> b >> c;

	cout << "int:" << a << endl;
	cout << "double:" << b << endl;
	cout << "char:" << c << endl;
	return 0;
}

三、缺省参数

  • 缺省参数是声明或定义一个函数是为函数的参数指定一个缺省值,在调用该函数时,如果没有指定实参,则采用该形参的缺省值,否则使用指定的实参。缺省参数分为全缺省和半缺省
  • 全缺省即全部形参给缺省值,半缺省即部分形参给缺省值,C++规定半缺省参数必须从左往右依此给缺省值,不能间隔跳跃给缺省值
  • 带缺省参数的函数调用,C++规定必须从左到右依此给实参,不能跳跃给实参
  • 函数声明和定义分离时,缺省参数不能在声明和定义中同时出现,规定必须函数声明给缺省值
#include<iostream>
using namespace std;

//全缺省
void Add1(int a = 0, int b = 0, int c = 0)
{
	cout << "全:" << a + b + c << endl;
}
//半缺省
void Add2(int a, int b = 0, int c = 0)
{
	cout << "半:" << a + b + c << endl;
}

int main()
{
	Add1();
	Add1(10);
	Add1(10,20);
	Add1(10,20,30);
	Add2(0);
	Add2(10,20);
	Add2(10,20,30);
	return 0;
}

四、函数重载

C++支持在同一作用域出现同名函数,但需要这些同名函数的形参不同,可以是参数个数不同、参数类型不同,或者参数类型相同但类型顺序不同,因为这样可以通过形参明显分辨出需要调用的是哪个函数

#include<iostream>
using namespace std;


//参数个数不同
int Add(int a, int b)
{
	return a + b;
}

int Add(int a)
{
	return (a + b) * 5;
}

//参数类型不同

int Add(double a, double b)
{
	return (a + b) * 10;
}

//参数类型相同但类型顺序不同
double Add(double a, int b)
{
	return 20*(a + b);
}

double Add(int a, double b)
{
	return 30*(a + b);
}

int main()
{
	cout << Add(10, 10) << endl;
    cout << Add(10) << endl;
	cout << Add(10.0, 10.0) << endl;
	cout << Add(10.0, 10) << endl;
    cout << Add(10, 10.0) << endl;
	return 0;
}

要注意的是不能出现要调用的函数无法分辨的情况

#include<iostream>
using namespace std;
void Add()
{
    return 10+20;
}

Void Add(int a = 20)
{
    return a + 20;
}

int main()
{
    cout << Add() << endl;
    return 0;
}

像这种情况,就会因为不知道要调用哪个函数而报错

五、引用

1、引用的概念和定义

引用不是新定义一个变量,而是给已经存在的变量取一个别名,编译器不会为引用变量和开辟内存空间,而是和引用的变量共用同一个内存空间,就比如秦始皇和嬴政都指向同一个人。

引用的底层代码也是通过指针实现的

类型& 引用别名 = 引用对象;
#include<iostream>
using namespace std;

int main()
{
	int a = 100;
	int& b = a;
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << "&a:" << &a << endl;
	cout << "&b:" << &b << endl;//可以看出 a、b 的地址是相同的,a 、b共用同一个空间
	++b;
	cout << "a:" << a << endl;//

	int c = b;//这里不是新建引用别名,而是给 c 赋值
	cout << "c:" << c << endl;
	cout << "&c:" << &c << endl;
	return 0;
}

2、引用的特性

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用一旦引用一个实体,不能再引用其他实体(指针可以指向某一个地址,但可以修改,指向另一个地址)

3、const 引用

可以引用一个 const 对象,但是必须用 const 引用,引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大

#include<iostream>
using namespace std;

int main()
{
	int a = 100;
	int& b = a;
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << "&a:" << &a << endl;
	cout << "&b:" << &b << endl;
	++b;
	cout << "a:" << a << endl;

	int c = b;
	cout << "c:" << c << endl;
	cout << "&c:" << &c << endl;

	const int d = 100;
	const int& e = d;
	cout << "d:" << d << endl;
	cout << "e:" << e << endl;

	int f = 100;
	const int& g = f;
	cout << "f:" << f << endl;
	cout << "g:" << g << endl;
	return 0;
}

4、指针与引用的关系

  • 语法概念上引用是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
  • 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
  • 引用在初始化时引用⼀个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
  • 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
  • sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8字节)
  • 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全⼀些。

六、inline

  •  用 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就不需要建立栈帧,可以提高效率

  • 编译器只会选择性展开内联函数,使用于频繁调用且短小函数,对于递归函数或代码多的函数,加上 inline 也会被编译器忽略,因为会增加代码量( 比如一个代码量为 4 的内联函数 和一个代码量为 20 的内联函数,在10000条代码中展开后  20*10000  远大于  4*10000 ,代码量大大增加,反而影响程序运行效率)

  • C语言实现宏函数也会在预处理时展开,但实现宏函数非常复杂且容易出错,且不方便调试,所以C++设计了内联函数就是为了替代C的宏函数

  • inline 不建议声明和定义分离到两个文件,分离会导致链接错误,因为 inline 被展开,没有函数地址,链接时会报错

  • vs编译器 debug 版本下默认不展开 inline ,方便调试

#include<iostream>
using namespace std;

inline int Add(int a, int b)
{
	a++;
	a++;
	a++;
	return a + b;
}

int main()
{
	cout << Add(10 - 1, 20 + 22) * 10 << endl;
	return 0;
}

七、nullptr

  • NULL实际是一个宏,在C头文件(stddef.h)中,可以看到
#ifndef NULL
     #ifdef __cplusplus
         #define NULL    0
     #else
         #define NULL    ((void *)0)
     #endif
 #endif
  •  C++中 NULL 可能会被定义为字面常量 0 ,或者在C中被定义为无类型指针(void*)的常量,这样会出现以下情况
#include<iostream>
using namespace std;

void i(int a)
{
	cout << "int a" << endl;
}

void i(int* a)
{
	cout << "int* a" << endl;
}

int main()
{
	i(NULL);
	return 0;
}

调用时会出现只能调用第一个 i() 函数的情况,或者

i((void*)NULL);

 会报错

  • C++11中引⼊nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换成任意其他类型的指针类型。使⽤nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,⽽不能被转换为整数类型。
#include<iostream>
using namespace std;

void i(int a)
{
	cout << "int a" << endl;
}

void i(int* a)
{
	cout << "int* a" << endl;
}

void d(double e)
{
	cout << "double e" << endl;
}

void d(double* e)
{
	cout << "double* e" << endl;
}

int main()
{
	i(NULL);
	i((int*)NULL);
	i(nullptr);

	d(0.0);
	d((double)NULL);
	d(nullptr);
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值