C++1节:C++的介绍,命名空间,类型,四种函数

今天跟兄弟闲聊的时候,他抱怨说,Python是C++写的,Java是C++写的...而C++呢,C写的。就好像在说,你看,别墅是砖磊的,楼是砖磊的,而砖自己呢,粘土做的,有点low的感觉。不过这也侧面说明了C++的地位。C++以其较好的兼容性和高执行效率,迄今仍是主流编程语言之一,在某些场景不可替代(某些重要系统考虑速度的时候)。这使得C++在以下领域不可或缺。

C++的应用领域

1)游戏(魔兽世界听过吧)
2)科学计算(https://www.cnblogs.com/xiexiaokui/archive/2010/05/20/1740353.html
3)网络通信(ACE框架)
4)操作系统和设备驱动(看看Windows自己)
5)其它(嵌入式、编译器、脚本引擎...)

C和C++区别

C和C++到底有什么区别呢?简单说就是
1)都是编译型语言
2)都是强类型语言,但是C++更强
3)C++去除了C中不好特性
4)C++中增加很多好的特性(面向对象语法),比C语言更适合大型软件开发。

我记得在我学STL的时候,我的老师很不屑的说,别的(编程语言)能做的,C++都能做,而C++都能做的,别的做不了。于是用文言文形式的注释,以简练优美的语言,深入浅出的讲解方式,凝练而精致的代码,向我们描述STL的强大和优雅。从那时候起我就渴望,以后一定要做一个优秀的C++程序员,不为别的,就为了想写什么就能写什么!也许这条路很长,也许生活会拖慢进取的脚步,但是只要在路上,总会有所成就!本课程将总结C++Primer重点内容,对C++语法做一个梳理。

第一个C++程序

#include <iostream>
//#include <stdio.h>//C风格
#include <cstdio>//C++风格,语义和上面等价

int main(void)
{
    printf("hello world!\n");
    std::cout << "hello world!" << std::endl;
    int i;
    float f;
    std::cin >> i >> f;
    printf("i=%d,f=%g\n",i,f);
    std::cout << "i=" << i << ",f=" << f << std::endl; 
    return 0;
}

1 linux下编译方式:
1)gcc xx.cpp -lstdc++
2)g++ xx.cpp //g++自动链接标准C++库

2 文件扩展名:C++中源文件一般以.cpp结尾,但也有其他
1)xx.cpp //推荐使用
2)xx.cc
3)xx.C
4)xx.cxx


3 头文件
#include <iostream>
#include <stdio.h> ==> #include <cstdio>


标准输入和输出


1)cin对象表示标准输入//类似scanf
eg:
   int a;
   //scanf("%d",&a);
   cin >> a;//从标准输入设备提取一个整形数放到变量a中
   ">>":提取运算符
eg:
   int a;
   double d;
   //scanf("%d%lf",&a,&d);
   cin >> a >> d;    

2)cout对象表示标准输出//类似printf
eg:

   int a = 100;
   //printf("%d\n",a);
   cout << a << endl;//把数据a插入到标准输出设备

 "<<":插入运算符    
eg:

   int a = 100;
   int d = 3.14;
   //printf("%d,%lf\n",a,d);//100,3.14
   cout << a << ',' << d << endl;//100,3.14

一 命名空间(或者叫名字空间)

一个命名空间的定义包含两部分:首先是关键字namespace,随后是命名空间的名字。在命名空间名字后面是一系列由花括号括起来的声明和定义。只要能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板和其它命名空间。命名空间结束后无须分号,这一点与块类似。和其它名字一样,命名空间的名字也必须在定义它的作用域内保持唯一。命名空间既可以定义在全局作用域内,也可以定义在其它命名空间中,但是不能定义在函数或类的内部。

1 名字空间的作用
1)避免名字冲突
2)划分逻辑单元

 

2 定义名字空间
namespace 名字空间名{
   名字空间成员1;
   名字空间成员2;
   ...
}
eg:
namespace ns1{
   int x;//全局变量
   void func(){} //全局函数
   struct A{}; //自定义类型
   namespace ns2; //名字空间
}

注意:1 命名空间可以是不连续的,命名空间可以定义在几个不同的部分。拿函数来说,函数定义一次,多次调用,这ok。而命名空间可以在不同地方多次定义(里面的成员名称不能相同)。2 通常来说#include应该放在命名空间前,如果放在名字空间里,那这个头文件里的变量、函数等都是该命名空间里的了,使用时需要 这样YourNameSpace::YourMember

3 名字空间使用
1)通过作用域限定符“::”
   名字空间名::访问问的成员;
eg:
  int main(){
     //访问ns1名字空间中x变量
     x = 100;//error,名字空间里面成员不能直接访问
     ns1::a = 100;//ok
     func();//error
     ns1::func();//ok
  }
eg:
   //std是标准C++库中已经定义好的名字空间,称为标准名字空间,所有C++库中全局函数、全局变量都在该名字空间中。
   std::cout << "hello world" << std::endl;

下面是代码示范:

#include <iostream>

//定义名字空间
namespace ns1{
    void func(void){
        std::cout << "ns1名字空间中的func函数"
            << std::endl;
    }
}
int main(void)
{
    ns1::func();//调用ns1中的函数
    return 0;
}

2)名字空间指令
using namespace 名字空间名;
在该条指令以后的代码中,指定名字空间中的成员都可见,访问其中成员可以省略作用域限定。   它的有效范围从using声明的地方开始,一直到using声明所在的作用域结束为止。在此过程中,外层作用域的同名实体将被隐藏。
 

using namespace std;//全局作用域
int main(void){
   cout << "hello world!" << endl;//前面不引用std
   //如果这句using namespace std;不写,则需要这样
   std::cout << "hello world!" << std::endl;
}


3)名字空间声明
  using 名字空间名::名字空间成员;
  将名字空间中的特定成员引入当前作用域,在该作用域中访问这个成员可以省略作用域限定。
eg:
  namespace ns{
     int i1;
     int i2;
  }     
  int main(){
     using ns::i1;
     i1 = 100;//ok
     i2 = 200;//error
     ns::i2 = 200;//error,未声明        
  }

4 无名名字空间(unnamed namespace)
   不属于任何名字空间的全局变量或函数,将被编译器自动放入无名名字空间中,引用格式如下。
   ::无名名字空间成员;

#include <iostream>
using namespace std;
namespace A
{
    int a = 100;
    namespace B            //嵌套一个命名空间B
    {
        int a =20;
    }
}

int a = 200;//定义一个全局变量,不属于任何名字空间,自动在无名名字空间::里


int main(int argc, char *argv[])
{
    cout <<"A::a ="<< A::a << endl;
    cout <<"A::B::a ="<<A::B::a << endl;
    cout <<"a ="<<a << endl;
    cout <<"::a ="<<::a << endl;

    int a = 30;
    cout <<"a ="<<a << endl;
    cout <<"::a ="<<::a << endl;

    return 0;
}


 结果:

A::a =100  
A::B::a =20
a =200      //全局变量a
::a =200
a =30       //局部变量a
::a =200   

注意:一个未命名的命名空间可以在某个给定的文件内不连续,但是不能跨越多个文件

5 名字空间嵌套//了解
namespace china{
   namespace beijing{
       char* name = "金亮";
   }
   namespace chengdu{
       char* name = "一虎";
   }
}
cout << china::beijing::name << endl;//金亮
cout << china::chengdu::name << endl;//一虎

拓展:

6 内联命名空间:C++11新标准引入了一种新的嵌套命名空间,称为内联命名空间(inline namespace)。和普通的嵌套命名空间不同,内联命名空间中的名字可以被外层命名空间直接使用。定义内联命名空间的方式是在关键字namespace前添加关键字inline。关键字inline必须出现在命名空间第一次定义的地方,后续再打开命名空间的时候可以写inline,也可以不写。

 #include <iostream>
 using namespace std;
 inline namespace A
 {
     inline void f(){
         std::cout << __FUNCTION__ << __LINE__ << std::endl;
     };  
 }
 int main(int argc, char *argv[])
 {
     f();
 }
 

结果:

f6

拓展:模板特例化

模板特例化必须定义在原始模板所属的命名空间中。和其它命名空间名字类似,只要我们在命名空间中声明了特例化,就能在命名空间外部定义它了。

 #include <iostream>
 using namespace std;
 namespace ns{ 
 //原始类模板
 template<typename T1,typename T2> 
 class One{
     public:
         void fun(T1 v1,T2 v2){
             std::cout << "v1 = " << v1 << std::endl;
             std::cout << "v2 = " << v2 << std::endl;
         }   
 };
//全特化类模板
 template<>
 class One<int,double>
 {
     public:
         void fun(int v1,double v2){
             std::cout << "v1(int) = " << v1 << std::endl;
             std::cout << "v2(double) = " << v2 << std::endl;
         }   
 };
 }//end ns

 int main(int argc, char *argv[])
 {
     using ns::One;//先用using指令声明One
     One<int,double> one;
     one.fun(123,12.3);
     return 0;
 }

结果:

v1(int) = 123
v2(double) = 12.3

 

二 C++中的类型

1 结构体
1)定义结构体变量时,可以省略struct关键字。
2)结构体中里面可以定义函数,称为成员函数,在成员函数中可以访问成员变量。

2 联合体(了解)
1)定义联合体变量时,可以省略union关键字
2)支持匿名联合

3 枚举
1)定义枚举变量时,可以enum关键字
2)C++枚举看做一种独立数据类型,而C中枚举本质就是整形数。
eg:
   enum COLOR{RED,GREEN,BLUE};
   COLOR c;
   c = 100;//C中ok,C++中error
   c = RED;//ok

4 字符串

4.1 回顾C中字符串
1)双引号常量字符串 
  "hello world"
2)字符串指针:char *
3)字符数组:char arr[..];   
eg:
  char arr[6] = "hello";
  strcpy(arr,"jiangguiliang");//内存越界,危险
  char* p = "world";
  strcpy(p,arr);//段错误
  p = "jiangguiliang";//ok
  arr = "jiangguiliang";//error
  
4.2 C++兼容C中字符串,同时增加string类型,专门表示字符串
1)定义字符串
   #include <string>  
   string s;//定义一个空字符串
   string s = "hello";
   string s = string("hello");//和上面等价
   string s("hello");//和上面等价
   cout << s << endl;//cout可以直接输出string类型的字符串

2)字符串的基本操作
   +  +=     字符串连接
   eg:
   string s1 = "hello";
   string s2 = "world";
   s1 += s2;//s1 = s1 + s2
   cout << s1 << endl;//"helloworld"
   
   =          字符串的拷贝
   eg:
   string s1 = "hello";
   string s2 = "world"; 
   s1 = s2;
   cout << s1 << endl;//world
   
   < <= > >=    字符串的比较大小
   == !=    比较字符串是否相同
   eg:
   string s1 = "hello";
   string s2 = "world"; 
   if(s1>s2){
       cout << "s1 > s2" << endl
   }
   else{
       cout << "s1 <= s2" << endl;//ok
   }
   
   可以用 [ ] 获取字符串中指定下标的字符
   eg:
   string s = "hello";
   s[0] = 'h';
   
3)string类型中常用的成员函数
   size()/length(); //获取字符串的长度
   c_str();//将string转换为char*风格的字符串

eg:

string s = "this is a test";

s.size();//得到字符串实际长度

char *ps = s.c_str();

5 布尔类型

5.1 bool类型是C++中基本数据类型,专门表示逻辑值:
  true表示逻辑真,false表示逻辑假
5.2 bool类型在内存占一个的内存:1表示true,0表示false
5.3 bool类型的变量可以接收任意类型的表达式的值,其值非0(NULL)则为true,零为false

6 操作符别名(了解)
&&  --》  and
||  --》  or
{   --》  <%
}   --》  %>
....

三 C++中的函数

函数是一组一起执行一个任务的语句,以{}开始结束。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。声明格式如下:

函数类型名称  函数名称(形式参数列表)
{
        语句1;
        语句2;
         ...
        return 返回值;
}

函数声明告诉编译器函数的名称、返回类型和参数。函数定义提供了函数的实际主体,也就是语句。在调用函数时,格式如下:

函数名称(实际参数列表);

以上是标准C语言的函数,C++中在此基础上,发展了一些新的特性,如函数重载,缺省函数,哑元参数,内联函数,下面一一说明:

1 函数重载:在相同的作用域中,定义同名不同的参函数,这样的函数构成重载关系。(函数重载和返回类型无关)调用重载关系的函数时,编译器将根据实参和形参的匹配程序,自动选择最优的匹配版本。其本质是C++编译器通过对函数进行换名,将参数类型信息整合到新的名字中,解决函数重载与名字冲突的矛盾(可理解为,参数类型也是函数名的一部分)。

 g++4.8的选择顺序是: 完全匹配>常量转换>升级转换>降级转换>省略号匹配

#include <iostream>
using namespace std;
//char->int:升级转换
void bar(int i){
    cout << "bar(1)" << endl;
}
//char->const char:常量转换
void bar(const char c){
    cout << "bar(2)" << endl;
}
//short->char:降级转换
void func(char c){
    cout << "func(1)" << endl;
}
//short->int:升级转换
void func(int i){
    cout << "func(2)" << endl;
}
//short->long long:过分的升级转换
void func(long long l){
    cout << "func(3)" << endl;
}
//省略号匹配,最差
void hum(int i,...){
    cout << "hum(1)" << endl;
}
//double->int:降级转换
void hum(int i,int j){
    cout << "hum(2)" << endl;
}
int main(void)
{
    char c = 'A';
    bar(c);//调用第二个bar()
    short s = 10;
    func(s);//调用第二个func()
    
    hum(10,3.14);

}

有些面试题问extern "C" 声明的作用,就可以说,让C++编译器知道这是C风格的函数名,那么C程序就可以顺利调用它了。

 extern "C" void func();

2 函数的缺省参数(默认实参)
1)可以为函数的参数指定缺省值,调用该函数时,如果不给实参,就取缺省值作为相应的形参的值。
eg:
void mysend(
  int soctfd,void* buf,int size,int flag=0);
2)如果函数的声明和定义分开,缺省参数写在声明部分,而定义部分不写。
3)缺省参数必须靠右,如果一个参数有缺省值,那么这个参数的右侧所有参数都必须带有缺省值。
  void func(int a=10,int b){}//error
  void func(int b,int a=10){}//ok
  func(100);

#include <iostream>
using namespace std;

//注意函数重载引发的歧义错误
//void foo(int a){}
//函数声明
void foo(int a,int b = 200 ,int c = 100);
int main(void)
{
    foo(10);
    foo(10,20,30);
    return 0;
}
//函数定义
void foo(int a,int b/*= 200*/,int c/* = 100*/){
    cout << a << ',' << b << ',' << c << endl;
}


3 函数的哑元参数//了解 
1)定义:只有类型而没有形参变量名的形参称为参数。
eg:
  void func(int/*哑元*/){} 
  int main(){
     func(10);
  }
2)使用场景
-->为了兼容旧的代码
eg:
算法函数:
   void math_func(int a,int b){..}
使用者:
   int main(){
       math_func(10,20);
       ...
       math_func(30,40);
   }
升级算法函数:
   void math_func(int a,int = 0){..}
使用者:
   int main(){
       math_func(10,20);
       ...
       math_func(30,40);
   }

4 内联函数(inline)

1)定义
  使用inline关键字修饰的函数,表示这个函数就是内联函数,编译器会对内联函数做内联优化,避免函数调用的开销。内联函数和宏的区别在于:宏是由预处理器对宏进行替代,而内联函数是通过编译器控制来实现的。
  inline 返回类型 函数名(形参表){...} //内联函数
2)适用场景
--》多次调用小而简单的函数适合内联
--》调用次数极少获取大而复杂的函数不适合内联
--》递归函数不适合内联

*拓展:

a 任何在类的声明部分定义的函数都会被自动的认为是内联函数。

b 在内联函数中如果有复杂操作将不被内联。如:循环和递归调用。

c 将简单短小的函数定义为内联函数将会提高效率。

d 关键字inline必须与函数定义体放在一起才能使函数称为内联函数,仅将inline放在函数声明前面不起作用。

inline void Foo(int x, int y);  // inline仅与函数声明放在一起

void Foo(int x, int y)
{
   //.....
}
//而如下风格的函数Foo则成为内联函数:
void Foo(int x, int y);
inline void Foo(int x, int y) // inline与函数定义体放在一起
{
   //......
}

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值