C++基础梳理 2019.1.5(::作用域运算符、命名空间、using声明和using编译指令、C++与C语言的区别,const增强,const在c和c++中的链接性,const内存分配,引用

::作用域运算符

1、用于引用全局作用域,这是cpp对于c的扩展

2、使用std::cout ,说明作用域

#include<iostream>
using namespace std;

int atk=200;

void test(){
	int atk=100;
	cout<<"攻击力为:"<<atk<<endl;
	cout<<"攻击力为:"<<::atk<<endl;
}

int main(){
	test();
	return 0;
}

运行结果

 

 

 

 

命名空间

namespace命名空间主要用来解决命名冲突的问题。

1、命名空间下可以放函数变量结构体

2、命名空间必须定义在全局作用域

3、命名空间可以嵌套命名空间

4、命名空间是开放的,可以随时向原命名空间中添加内容(代码例子如下)

namespace A{
    int a=0;
}

.....一堆别的......

//此命名空间A会和上面的命名空间A合并
namespace A{
    int b=5;
}

5、命名空间可以匿名或者无名 。例子如下

namespace{
    int m_C=0;
    int m_D=0;
}

匿名命名空间相当于写了一个static int m_C   和一个   static int m_D静态变量。

静态变量的原则是只能在当前文件内使用。

6、命名空间可以起别名(例子如下)

namespace veryLongName{
    int a=0;
}

void test(){
    //用的时候,veryShortName和veryLongName都可以引用那个命名空间
    namespace veryShortName=veryLongName;
}

 

需要注意的坑

namespace A {
	struct X{};
	struct Y{};
	void f(int){}
	void g(X){}
}

namespace B {
	void f(int i) {
		//调用的是namespace B中的f
		f(i);
	}
	void g(A::X x) {
		//调用的是namespace A下的g(X)函数
		//根据参数找调用的函数,参数X在namespace A中进行定义,namespace A中存在g函数,因此
		g(x);
	}
	void h(A::Y y) {
		//调用的是namespace B下的h函数,因为查找namespace A中没有h函数
		//即,先查找了namespace A中,没找到再查找本namespace中是否存在调用的函数
		h(y);
	}
}

namespace C {
	void g(A::X x) {
		//调用的也是namespace A中的函数g
		g(x);
	}
}

 

使用示例如下

game1.h

#include<iostream>
using namespace std;

namespace LOL{
 void goAtk();   
}

game1.cpp

#include"game1.h"

void LOL::goAtk(){
    cout<<"LOL攻击实现"<<endl;
}

game2.h

#include<iostream>
using namespace std;

namespace King{
 void goAtk();   
}

game2.cpp

#include"game2.h"

void King::goAtk(){
    cout<<"王者荣耀攻击实现"<<endl;
}

main.cpp

#include<iostream>
using namespace std;
#include"game1.h"
#include"game2.h"

int main(){
    LOL::goAtk();
    King::goAtk();
    return 0;
}

 

 

 

 

using声明和using编译指令

 

using声明

使用using声明的时候,要避免二义性。例子如下

namespace King{
    int a=10;
}

void test(){
    int a=5;
    using King::a;
    cout<<a<<endl;
}

此时会发生二义性,因为using说明以后看到的变量a都是用King命名空间里面的,可是编译器又有就近原则,因此输出的时候不知道要输出哪一个了。

 

using编译指令

可以避免二义性,我只是打开了房间,你用不用是你的事情。例子如下

namespace King{
    int a=10;
}

void test(){
    int a=5;
    using King;
    cout<<a<<endl;
}

这里会输出5,因为用了就近原则。

 

 

 

 

C++与C语言的区别

c语言中没有函数的默认参数这一概念。

 

全局变量检测增强

在c语言,全局变量重定义会检测通过,但是C++无法通过,会报错。例子如下

int a;
int a=10;

 

函数检测增强

下面代码在C语言中会跑通,参数类型没写返回值也没写,也能跑通。

int test(m,h){

}

而且c中,调用函数传入的参数超过函数的参数个数也可以调用成功。例子如下

int test(m,h){

}

void get(){
    test(10, 10, 10);
}

 

类型转换增强

下面的代码在c中可以,在c++中不可以

char *a=malloc(sizeof(64));

 

struct增强

1、C语言中,struct中不能加函数。c++中,struct可以加函数。

2、C语言中,struct定义对象,一定要写struct关键字(例子如下).c++中可以不写struct关键字。

struct Person{
    char*name;
};

void test(){
    struct Person p1;
}

 

bool类型增强

c语言中没有bool类型。c++中有bool类型,该类型只有真(1)或假(0)。bool类型,非0的会转为1,0的还是0.

 

条件运算符增强

c语言里面返回的是c++里面返回的是变量

 

 

 

 

const增强

c语言中,全局的const变量一旦初始化之后便不能修改,但是函数内部的变量可以修改,通过指针,指向const变量的地址,就可以绕过const去修改里面的值。例如

const int m_A=10;

void test(){
    //下面这句会报错,因为m_A不可修改
    m_A=100;

    //通过指针,绕过局部变量的const,对该地址上的值进行修改
    const int m_B=20;
    int *p=(int*)&m_B;
    *P=200;
}

因此局部的const变量是伪常量,并不能初始化数组的长度

c++中,局部的const变量你没办法修改。例子如下:

     

 

 

为什么指针绕不过c++的局部const?就是为什么c++中用指针改不了局部const的值?

 

那么指针做了什么?

 

链接性

C语言中const默认外部链接(就是外部文件能看见)

c++中默认是内部链接,所以下图中找不到别的文件里面写的const变量。

 

如果你想让外部文件找到const变量,你给他加个extern提高作用域。如下图所示:

 

 

 

const内存分配

c++中,const变量不分配内存,但是

1、对const变量取地址,会分配临时内存

2、给const变量加上extern关键字,编译器也会给const变量分配内存

3、用普通变量初始化const变量,会分配内存。例子如下

void test(){
    int a=10;
    const int b=a;//会分配内存
}

如何验证?只要分配内存的,都可以通过指针绕过const去把你的内容改掉。

4、自定义数据类型,加const也会分配内存。如下

struct Person{
    string m_Name;
    int m_Age;
}

void test(){
    const Person p1;

    //检测是否真的分配了内存
    Person *p=(Person*)&p1;
    p->m_Name="德玛西亚";
    (*p).m_Age=18;

    cout<<"姓名:"<<p1.m_Name<<"年龄:"<<p1.m_Age<<endl;

}

 

 

尽量用const代替#define

解决方案是用一个常量替换上面的宏

const int max=1024;

 

 

 

 

引用

基本用法

引用 是c++对c的扩充

1、引用基本语法  type &别名=原名;

2、引用必须初始化。初始化后不可修改。

3、对数组建立引用 

方法一

int arr[10]={0,1,2,3,4,5,6,7,8,9};

//给数组起别名
int(&pArr)[10]=arr;
for(int i=0; i<10; i++){
    cout<<pArr[i]<<" ";
}

cout<<endl;

方法二

int ar[10]={0,1,2,3,4,5,6,7,8,8};

//一个具有10个int类型元素的数组
typedef int(ARRAYREF)[10];
ARRAYREF &pArr2=arr;

for(int i=0; i<10; i++){
    cout<<pArr[i]<<" ";
}

cout<<endl;

 

 

引用的注意事项

1、引用必须是一块合法的内存空间

2、不要返回局部变量的引用。如果实在需要返回局部变量的引用,可以这么做

int& test(){
    static int a=10;
    return a;
}

如果函数的返回值是引用,那么这个函数可以作为左值。

test()=1000;//相当于写了 a=1000;

 

 

引用的本质

引用的本质在c++内部实现是一个指针常量

type &ref=val;//type* const ref=&val;

 

 

引用的使用场景

1、指针的引用

早期版本如下:

 

利用指针引用开辟空间

 

 

2、常量引用

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值