::作用域运算符
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、常量引用