Day001---C++入门

目录

1. 命名空间

1.1 使用命名空间的目的 

1.2 命名空间的定义

1.3 命名空间的使用

2. C++输入&输出

3. 缺省参数

4. 函数重载

5. 引用

6. 内联函数

7. auto关键字(C++11)

8. 基于范围的for循环(C++11)

9. 指针空值---nullptr(C++11)


1. 命名空间

1.1 使用命名空间的目的

        为避免全局域中的函数、变量、类的名字的冲突,对标识符的名称进行本地化。关键字:namespace。

        命名空间不影响变量的生命周期只是限定域,所以在命名空间内变量是全局域,在静态区开辟空间。不影响默认查找规则:先找局部、再找全局。

        访问命名空间里面的变量:命名空间名:: (平原如全局,命名空间砌筑了围墙,防止都能看见,起冲突)

        std为C++官方库内容定义的命名空间名字,如下面的bit

1.2 命名空间的定义

        1.2.1 正常定义命名空间成员可以是变量、函数、类型(结构体等)

namespace bit
{
     // 命名空间中可以定义变量/函数/类型
     int rand = 10;
     int Add(int left, int right)
     {
         return left + right;
     }
     struct Node
     {
         struct Node* next;
         int val;
     };
}
int main()
{
    printf("%d\n",bit::a);
    printf("%d\n",bit::Add(1,2));
    // 访问命名空间的结构类型
    struct bit::Node cur;
    return 0;
}

        1.2.2 嵌套命名空间

namespace N1
{
    int a;
    int b;
    int Add(int left, int right)
     {
         return left + right;
     }
    namespace N2
     {
         int c;
         int d;
         int Sub(int left, int right)
         {
             return left - right;
         }
     }
}
int main()
{
    N1::a = 1;
    // 嵌套访问
    N1::N2::c = 2;
    printf("%d\n",N1::a);
    printf("%d\n",N1::Add(1,2));
}

        1.2.3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中,比如:.h文件与.c文件。

 1.3 命名空间的使用

        1.3.1 不展开写法:实际工程中使用

namespace N1
{
    int a;
    int b;
}
int main()
{
    N1::a = 1;
    N1::b = 2;
}

        1.3.2 部分展开写法:若命名空间内有变量名字、类型名字、函数名字使用次数较多,其他使用次数不多,为方便起见,可使用部分展开

using N1::a; // 部分展开a,访问时就方便了
namespace N1
{
    int a;
    int b;
}
int main()
{
    a = 1;
    N1::b = 2;
}

        1.3.3 完全展开写法:将命名空间内的名字全部打开,能直接访问(以c++命名空间为例)

using namespace std;
using namespace N1;
namespace N1
{
    int a;
    int b;
}
int main()
{
    cout << a << b << endl;// 将std与N1全部展开
}
1.4 std命名空间的使用惯例:
std是C++标准库的命名空间,如何展开std使用更合理呢?
1. 在日常练习中,建议直接using namespace std即可,这样就很方便。
2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。

2. C++输入&输出

#include<iostream>
using namespace std;
int main()
{
    float a;
    int b;
    double c;
    cin >> a; // 自动识别类型其实是函数重载
    cin >> b >> c; // 自动识别类型其实是函数重载
    cout << "hello world" << endl;
    return 0;
}
    
说明:
1. 使用 cout 标准输出对象 ( 控制台 ) cin 标准输入对象 ( 键盘 ) 时,必须 包含 < iostream > 头文件
以及按命名空间使用方法使用 std
2. cout cin 全局的流对象 endl 是特殊的 C++ 符号,表示换行输出,他们都包含在包含 <iostream >头文件中。
3. << 是流插入运算符, >> 是流提取运算符
4. 使用 C++ 输入输出更方便,不需要像 printf/scanf 输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
5. 实际上 cout cin 分别是 ostream istream 类型的对象, >> << 也涉及运算符重载等知识.
注意:早期标准库将所有功能在全局域中实现,声明在 .h 后缀的头文件中,使用时只需包含对应
头文件即可,后来将其实现在 std 命名空间下,为了和 C 头文件区分,也为了正确使用命名空间,
规定 C++ 头文件不带 .h ;旧编译器 (vc 6.0) 中还支持 <iostream.h> 格式,后续编译器已不支持,因
推荐 使用 <iostream>+std 的方式。

3. 缺省参数

        缺省参数是声明函数或者定义函数时对形参进行初始化的操作,若在函数调用时,没有给出实参值,这时使用的是形参的缺省参数,否则使用指定的实参值。

                                // 全缺省参数
void FUNC(int a = 10;int b = 20;int c = 30)
{
    cout << a << b << c << endl; 
    // a = 10;b = 20;c = 30  
}
void FUNC(int a = 10;int b = 20;int c = 30)
{
    cout << a << b << c << endl;
    // a = 30;b = 20;c = 30   
}
void FUNC(int a = 10;int b = 20;int c = 30)
{
    cout << a << b << c << endl;
    // a = 30;b = 20;c = 10   
}
int main()
{
    FUNC();
    FUNC(30,20);
    FUNC(30,20,10);
    return 0;
}
                                // 半缺省参数
void FUNC(int a;int b = 20;int c = 30)
{
    cout << a << b << c << endl; 
    // a = 30;b = 20;c = 30  
}
void FUNC(int a;int b;int c = 30)
{
    cout << a << b << c << endl;
    // a = 30;b = 20;c = 10   
}
int main()
{
    FUNC(30,20);
    FUNC(30,20,10);
    return 0;
}
        1. 半缺省参数必须从右往左依次连续缺省,不能间隔缺省(FUNC(int a=1,int b ,int c=20)这种不行)
        2. 缺省参数不能在函数声明和定义中同时出现
        3. 缺省值必须是常量或者全局变量
        4. C语言不支持(编译器不支持)

4. 函数重载

        函数重载:是函数的一种特殊情况, C++ 允许在 同一作用域中 声明几个功能类似 的同名函数 ,这些同名函数的形参列表 ( 参数个数 或 类型 或 类型顺序 ) 不同 ,常用来处理实现功能类似数据类型
不同的问题(即使函数名字相同,但只要参数个数or参数类型or参数顺序任一不同,均可认为是不同的函数)。
#include<iostream>
using namespace std;
        // 1、参数类型不同
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()
{
     Add(10, 20);
     Add(10.1, 20.2);
     f();
     f(10);
     f(10, 'a');
     f('a', 10);
     return 0; 
}

         函数重载基本原理:函数名修饰规则:g++的函数修饰后变成【_Z+函数长度 +函数名+类型首字母】,返回值不同不构成函数重载,是因为调用时的二义性,无法区分调用时不指定返回值类型。

 5. 引用

        5.1 可以看出引用只是对原变量起了个别名,他们都维护同一块空间(不单独开空间),变量地址都相同。以下是使用场景:

                        // 做输出型参数
#include<iostream>
// m和n分别是cc与dd的别名,不是新开辟的空间的名字,是原来的空间的别名
void swap(int& m, int& n)
{
	int tmp = m;
	m = n;
	n = tmp;
}

int main()
{
	int cc = 1, dd = 2;
	swap(cc, dd);
	return 0;
}
                            // 做参数
struct ListNode
{
	struct ListNode* next;
	int val;
};
// 等价于struct ListNode*phead,phead是一个指针变量,形参接受也是一个指针变量
void ListPushback(struct ListNode*& pphead,int x)
{
}
int main()
{
	struct ListNode* phead;
	ListPushback(phead, 3);
	ListPushback(phead, 4);
	ListPushback(phead, 5);
	return 0;
}
 
// 传引用返回
int& count()
{
    static int n = 0; 
    n++;
    return n; 
}

// 传值返回
int count()
{
    static int n = 0;// n 在静态区里面,不在count的栈帧内
    n++;
    return n;// 若n比较小,一般在寄存器开辟临时空间,否则会存在当前函数的上一层栈帧(由高地址向低地址,函数栈帧向下开辟)
             // return n 会产生一个临时变量,此临时空间类型为int
}

int main()
{
    int ret = count();
    return 0;
}

         ​​​

         

注意:1、出了函数作用域,如果返回变量还在,才能使用引用返回(变量在堆上、静态区创建的)
2、出了函数作用域,返回变量不存在了,不能使用引用返回,因为引用返回的结果是未定义的

 正确玩法

引用做返回的优点:1、减少拷贝,提高效率。2、修改返回值(提到了单链表Modfine接口)
引用做参数的优点:1、减少拷贝,提高效率。2、输出型参数
引用权限问题:(const相关上)
#include<iostream>

// 为减少拷贝,采用引用做参数,这样就会有问题
// 一般用引用做参数会用到const,不然实参的权限比形参小,就会有权限放大的情况
void FUNC(const int& x)
{
}
int main()
{
	int a = 10;
	// 权限平移/不变
	int& ra = a;
	
	const int b = 20;
	// 权限放大的情况--b的权限为只读,rb的权限为可读可写
	int& rb = b; //错误--放大情况不允许,在函数传参时也有这种情况

	// 权限缩小(指rra的权限缩小)的情况--a的权限为可读可写,rra的权限为可读
	const int& rra = a;
	rra++; // 错误
	a++;
	FUNC(a);
	FUNC(b);
	FUNC(rra);

	std::cout << a << std::endl; // 11
	std::cout << rra << std::endl; // 11
	return 0;
}

引用权限问题:(const相关下)

int count()
{
	int n = 0;
	n++;
	return n;
}
#include<iostream>
int main()
{
	const int& b = 10; // const修饰的引用变量可以为常量
	double d = 12.34;
	std::cout << (int)d << std::endl;// 12
	//int ri = d;// 这叫类型转换,中间会产生临时变量
	const int& ri = d;// 和上面类似,ri是临时变量的别名,临时变量的常量性
	std::cout << ri << std::endl;// 12

	const int& ret = count();// return n中的n也是个临时变量,若要用引用接收,则要用const修饰的
	return 0;
}

6. 内联函数

        形如函数返回值前加上inline修饰,即为内联函数

7. auto关键字(C++11)

        引用是给变量取别名,则auto关键字是给类型取别名,typedef也可以对类型进行取别名,但是在遇到对const修饰的变量进行赋值时,typedef后会不知道原类型的数据,

8. 基于范围的for循环(C++11)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值