C++的新的风格中,取消了头文件的扩张名
C语言是一种面向过程的编程语言。
面向过程的编程思想的核心就是:功能分解,自上而下,逐层分解,逐层细化。
程序 = 数据结构 + 算法
而C++加入了面向对象的特性。
面向对象(Object Oriented Programming) , 简称OOP。
面向对象有三大特性:封装、继承、多态
封装:把客观的事务抽象成一个类(将数据和方法打包在一起,加以权限的区分,达到保护
并安全使用数据的目的)
继承:继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征
和能力
继承的目的是:避免公用代码的重复开发,减少代码和数据冗余
多态:多态可以简单地概括为“一个接口,多种方法”,字面意思为多种形态。程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念
作用域运算符是用来表明数据、函数的归属的
作用域运算符就是两个冒号
::
#include <iostream> int a ; int main(){ int a = 10; std::cout<<a<<std::endl;//不加作用域运算符默认是局部的a std::cout<<::a<<std::endl;//加上作用域运算符默认使用全局的a return 0; }
命名空间,namespace,是用来解决C语言中函数名、变量名冲突的问题的
命名空间需要注意的点:
1.namespace命名空间的定义
//定义一个名字为A的命名空间(变量、函数) namespace A { int a = 100; } namespace B { int a = 200; } void test02() { //A::a a是属于A中 cout<<"A中a = "<<A::a<<endl;//100 cout<<"B中a = "<<B::a<<endl;//200 }
2.命名空间只能全局范围内定义
命名空间的数据和函数仍然是全局的作用域,就算是嵌套的命名空间,其内部的数据和函数也都还是全局的
下面这种做法是错误的
3.命名空间可嵌套命名空间
在命名空间里面还可以嵌套命名空间
namespace A { int a = 1000; namespace B { int a = 2000; } } void test03() { cout<<"A中的a = "<<A::a<<endl; //1000 cout<<"B中的a = "<<A::B::a<<endl; //2000 }
4.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中
也就是说,我们在一个工程中的都一处写了一个命名空间,到了后面又使用这个名字的命名空间,那么编译器就会把同一个名字的命名空间全部合并到一起
namespace A { int a = 100; int b = 200; } //将c添加到已有的命名空间A中 namespace A { int c = 300; } void test04() { cout<<"A中a = "<<A::a<<endl;//100 cout<<"A中c = "<<A::c<<endl;//200 }
5.命名空间 可以存放 变量 和 函数
namespace A { int a=100;//变量 void func()//函数 { cout<<"func遍历a = "<<a<<endl; } } void test05() { //变量的使用 cout<<"A中的a = "<<A::a<<endl; //函数的使用 A::func(); }
6.命名空间中的函数 可以在“命名空间”外定义
在同一个命名空间中,不论函数是在内部定义还是在外部定义,当函数内部使用同一个命名空间的数据的时候,不需要加作用域,当然加上也没有错,但是需要访问其他命名空间的数据或者函数的时候,就需要加上作用域运算符
1 namespace A { 2 int a=100;//变量 3 4 void func(); 5 } 6 7 void A::func()//成员函数 在外部定义的时候 记得加作用域 8 { 9 //访问命名空间的数据不用加作用域 10 cout<<"func遍历a = "<<a<<endl; 11 } 12 13 void funb()//普通函数 14 { 15 cout<<"funb遍历a = "<<A::a<<endl; 16 } 17 void test06() 18 { 19 A::func(); 20 funb(); 21 }
7.无名命名空间,意味着命名空间中的标识符只能在本文件内访问,相当于给这个标识
符加上了static,使得其可以作为内部连接
namespace后面可以不加名字,直接使用,这时候,这个无名的命名空间内部的数据和函数和普通的全局数据和函数没有什么区别,直接使用名字就可以调用了
如果普通的全局变量或者函数和无名命名空间的变量或者函数同名的话,在调用的时候就会又冲突,这个时候就没有办法再调用无名命名空间里面的了,但是全局的数据或者函数我们可以在前面加上两个冒号,也就是作用域运算符来使用
但是,普通的全局变量或者函数默认是外部链接属性的,但是在无名命名空间内部的变量或者函数就是内部链接属性的
void f(){ std::cout<<"全局的namespace"<<std::endl; } namespace{ void f(){ std::cout<<"无名命名空间的namespace"<<std::endl; } } int main(){ ::f(); return 0; }
8.命名空间可以取别名
namespace 新名字 = 旧名字
namespace veryLongName{ int a = 10; void func(){ cout << "hello namespace" << endl; } } void test(){ namespace shortName = veryLongName; cout << "veryLongName::a : " << shortName::a << endl; veryLongName::func(); shortName::func(); }
命名空间内的数据和函数有三种使用方式
- using namespace 命名空间名字
使用这种方式就是把命名空间全部展开,后面的使用的时候就不需要加作用域运算符了
但是如果在函数中直接展开的话,会容易和全局的造成冲突,不会和局部造成冲突,局部优先
1 namespace veryLongName { 2 int a=100; 3 void func(){cout<<"hello namespace"<<endl;} 4 } 5 void test07() 6 { 7 8 //使用veryLongName命名空间 9 using namespace veryLongName; 10 11 //出现的变量 从veryLongName命名空间中找 找不到 从其他地方中 12 cout<<"a = "<<a<<endl; 13 func(); 14 }
- 使用using将命名空间中成员引入
using N::b; int main() { printf("%d\n", N::a); printf("%d\n", b); return 0; }
但是这种方式会和局部同名的数据或者函数冲突,也就是说,如果命名空间和局部同时有同名的变量或者函数,就不能使用这种展开的方式
但是不会和全局冲突,此时命名空间优先与全局
- using声明碰到函数重载
namespace A { //函数重载 函数名+参数 组合代表是函数的入口地址 void func(){cout<<" 无参的func"<<endl;} void func(int a){cout<<" int的func"<<endl;} void func(int a,int b){cout<<" int int的func"<<endl;} } void test08() { //using指明 使用 A中的func 会对 所有的func起作用 using A::func; func(); func(10); func(10,20); }
标准命名空间,std
#include <iostream> //使用标准的命名空间std //std中所有成员名 可以直接使用 //cout endl cin都是命名空间std的成员 using namespace std; int main(int argc, char *argv[]) { std::cout << "Hello World!" << std::endl; cout << "Hello World!" << endl; return 0; }