C++基础1:C++新特性(命名空间,引用,指针,重载,内联)

C++新特性

1. c++简介:

C++这个词在中国大陆的程序员圈子中通常被读做“ C 加加”,而西方的程序员通常读 做“ C plus plus”,它的前身是 C 语言
C++是在 C 语言的基础上开发的一种集面向对象编程、泛型编程和过程化编程于一体的编程

1980 年,美国贝尔实验室的 Bjarne Stroustrup 博士及其同事在 C 语言的基础上,从 Simula67 中引入面向对象的特征,开发出一种过程性与对象性相结合的程序设计语言。最初称 为“带类的 C”, 1983 年取名为 C++。 此后, C++经过了许多次改进、完善,发展成为现在 的 C++。

目前的 C++具有两方面的特点:其一:C++是 C 语言的超集,因此其能与 C 语言兼容**;其 二**: C++支持面向对象的程序设计,使其被称为一种真正意义上的面向对象程序设计语言。 C++ 支持面向对象的程序设计方法,特别适合中型和大型的软件开发项目。从开发时间、费用到软件的重用性、可扩充性、可维护性和可靠性等方面, C++均具有很大的优越性

2. c++与 c 的区别:

2.1 c++与 c 的共同点:

C++和 C 语言都是编译型语言,也就是只有编译之后才能运行的,有些是不需要编译就 可以直接运行的,是通过解释器执行的,这种语言叫脚本语言,像== shell 脚本,Python, JavaScript 等==;

C++和 C 语言都是强类型语言,所有的标示符都必须有数据类型

a; a = 10; //error 
int a;a=10; //succeed

2.2 c++与 c 的不同:

2.2.1 编程思想变化:

对于初学者来说,仅需要明白: C++是在扩充了 C 面向对象过程功能的基础上,又增 加了面向对象的功能就可以了。下面列举了二者的一些区别。

从机制上: C 是面向过程的(但 C 也可以编写面向对象的程序); C++是面向对象 的,提供了类。但是, C++编写面向对象的程序比 C 容易。

从适用的方向: C 适合要求代码体积小的,效率高的场合,如嵌入式;C++适合更上层的,复杂的,例如大型游戏; Linux 核心大部分是 C 写的,因为它是系统软件, 要求极高的效率.

C++对 C 语言提供兼容,并且做了优化提供了更多的特性:

a.语言风格更加简洁
b.类型检查更加严格
int* pi = malloc(sizeof(int));// error 返回值需要强制转化
c.支持面向对象编程
d.支持运算符重载 :
1+1 = 2
一个人 + 10 //将运算符进行重载
e.支持异常处理 f.支持泛型编程

2.2.2 编程的基本变化

(1)文件的扩展名发生变化 :

C 语言中源文件: xxx.c
C++中源文件:.C/.cc/.cxx/.cpp(plus plus)
C 语言中头文件: xxx.h
C++中头文件: xxx.hpp / xxx.h

(2)引入头文件的变化:

C 语言中: #include
C++中: #include //iostream 输入输出

使用 C 语言中头文件:
#include 去掉.h,前面加 c
vi /usr/include/c++/4.6/cstdio 文件中包含的还是 stdio.h 文件

(3)输入输出的变化:
C 语言中:scanf/printf 函数
C++中:cin/cout 对象

(4)编译器的变化:
C 语言中:gcc/cc xxx.c
C++中: g++/c++ xxx.cpp
gcc/cc xxx.cpp -lstdc++

g++/c++ 的编译选项和 gcc/cc 一样:

-c 只编译不连接
-S 生成汇编文件
-o 指定输出文件名
-O 优化

(5)新增关键字和运算符:
C++在 C 语言基础上新增了一些保留字: class、 friend、 virtual、 inline、 private、public、 protected、 this、 string;也新增了一些运算符: new、 delete、 operator::。

3.命名空间:

using namespace std; //引入标准命名空间
使用标准命名空间,标准库中类以及函数等全部放在 std 的命名空间中

3.1.命名空间的学习和使用:
引入了命名空间(namespace)的概念,主要用于区分同名的函数、变量

3.2 自定义命名空间:

namespace 命名空间名字
{
变量、函数等 
}

注意:和结构体的格式非常相似,但是关键字不同,并且没有分号,用于作用域的限定, 并不是一种独立的数据类型

3.3 使用名字空间的方式:

(1)使用名字空间指令的方式声明命名空间
如:

using namespace std;

(2)使用作用域限定符

:: - 作用域限定符,相当于"的"
如:

std::cout << "大家好才是真的 好";

(3)使用名字空间声明的方式去使用名字空间中的部分内容
如:

using std::cout; 
using std::endl;
(endl:end of line .endl 除了写'\n'进外,还调用 flush 函数,刷新缓冲区,把缓冲区里的数据写入文件或屏幕.考虑效率就用'\n'.)
 cout << "大家好才是真的好" << endl;

3.4 无名名字空间:

如果一个标示符没有被置于任何名字空间中,则默认为无名/匿名名字空间中,可以 使用如下形式去访问标示符:

::无名名字空间成员名

3.5 扩展:

(1)同一个命名空间中的内容可以分开写
(2)命名空间中的函数声明和定义也可以分开,也就是函数的定义可以放在命名空间 的外面
(3)命名空间可以进行嵌套

4. 结构体、联合、枚举的不同:

4.1 结构体中的不同:

C 语言中:

struct Student/*结构体类型名*/ 
{ ... }; 
struct Student/*左边整体作为一个完整的数据类型*/ s;

typedef struct Student
{ ....}Student/*别名*/;

typedef struct
{....}Student/*别名*/;

C++中:
struct Student{…};
[struct] Student s;

(1)C++中的结构体定义变量时可以省略 struct 关键字
(2)C++中的结构体内部可以定义函数,并且函数内使用成员变量时不需要. ->之类的
(3)C++中的结构体中可以定义函数

4.2 联合的不同之处:

(1)定义联合变量的时候可以省略 union 关键字
(2)支持匿名联合:
如:

union un/*un 是联合类型名*/{..}; 
[union] un u;

union{...}; 匿名联合

4.3 枚举的不同之处:

(1)枚举类型在定义变量时也可以省略 enum 关键字
(2)C 语言的枚举 本质上就是整型,可以使用整数进行赋值
C++中的枚举 是一种独立的数据类型,不能使用整数进行赋值 (int 类型的值域 比 枚举类型的大)

5. 布尔类型 以及 引用:

5.1 布尔类型:

C 语言中:

bool #include<stdbool.h> 
int

C++中:
bool 类型是 C++中的基本数据类型,bool 类型的值有两个:true 和 false,其本质上 就是 1 和 0
bool 类型本质上就是一个单字节整数,任何基本数据类型都可以被隐式地转换为 bool 类型
注意: bool 类型定义变量,可以作为函数的参数和返回值类型,当然也可以定义指针类型

5.2 引用类型:

引用并不是一种独立的数据类型,类似于 C 中的指针,其实是变量的别名;
如:

int a = 10; 
int& b = a; => 给 a 起了个别名叫 b,b = 10; 
int& c = b; => int& c = a; c = 10;

5.2.1 引用和指针的区别:

(1)引用必须初始化,指针可以不初始化:

int& a; // error 
int* pa; // 野指针

(2)引用不可以为空,指针可以为空:

int& a = NULL; //error 
const int& a = NULL; //常引用 
const int& a = 11; // ok 
int* pi = NULL; //空指针

(3)引用不可以更换目标,指针可以:

int a = 10; 
int& b = a; 
int m = 20; 
b = m; => a = m; 赋值 

int* pi = &a; 
pi = &b

(4)可以定义指向指针的指针,但是不可以定义指向引用的指针:

如:

int a = 10; 
int* pa = &a;//一级指针 
int** ppa = &pa;//二级指针

int& b = a;//a 起别名为 b 
int& *pb = &b; //error

(5)可以定义引用指针的引用,不可以定义引用 引用的引用:
如:

int a = 10; 
int* pa = &a; 
int* &ra = pa; //ok

int& b = a; 
int&& rb = b; // error

(6)不能声明引用型数组,可以声明指针型数组:

int& arr[10]; //error 
int* arr[10]; //ok 
int arr[10]; //ok 
int (*arr)[10]; //ok

5.2.2 函数形参使用引用类型优点:

C++的函数允许利用引用进行参数传递,具有高效性和安全性。
(1)在进行实参和形参的结合时,不会为形参分配内存存储区,而是将形参作为实参的一个别名。使用引用传递函数的参数,形参和实参共用同一个内存存储区;而使 用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储区,实参变量 的值会赋给形参变量; 因此,当参数传递的数据较大时,用引用比用一般变量传递参 数的效率和所占空间都好。
(2)用引用能达到同指针传递同样的效果,则函数内对形参的操作相当于直接对实 参的操作,即形参的变化会影响实参。

建议:在 C++程序尽量去使用引用,而少使用指针,因为指针容易出现野指针, 容易出现段错误

5.2.3 引用作为函数的返回值:

永远不要返回对局部变量(包括函数的形参)的引用,可以返回 静态局部变量/全局 变量/动态内存/实参的引用/成员变量 的引用,这些返回值都是安全的

6. 类型转换与动态分配内存:

6.1.类型转换:

隐式类型转换: 一般从小 -> 大
显式类型转换(强制类型转换): 一般从大到小的转换

如:

char c ; 
int i = (int)c; //C 语言风格 
int i = int(c); //C++风格

6.1.1 四种类型转换符(转换算子):

(1)静态类型转换:

目标类型 变量名 =
static_cast<目标类型>(源类型变量);
功能:
如果在目标类型和源类型之间只要有一个方向上可以做隐式类型转换,那么在两个 方向上都可以做静态类型转换;反之,如果在两个方向上都不能做隐式类型转换,那么在 两个方向上都不能做静态类型转换

(2)常量类型转换

目标类型 变量名 = const_cast<目标类型>(源类型变量);
功能:主要用于去除指针/引用上的常属性
注意:试图通过 const_cast 去修改一个常量的值,那么后果是不确定的

(3)重解释类型转换

目标类型 变量名 = reinterpret_cast<目标类型>(源类型变量名);
功能:主要用于任意两种指针类型之间的转换,以及指针和整型之间的转换

(4)动态类型转换

目标类型 变量名 = dynamic_cast<目标类型>(源类型变量名);
功能:主要用于具有多态特性的父子类 指针/引用 之间的转换(以后讲到)

7. 函数的重载、缺省参数、哑元以及内联:

7.1 函数的重载:
(1)重载的概念:

在同一个作用域中,函数名相同,函数的参数列表不同构成重载关系,在不同的作用域 中遵循标示符隐藏原则

(2)函数重载的方式:

a.函数名相同,参数类型不同
b.函数名相同,参数个数不同
c.函数名相同,参数顺序不同
d.函数名相同,const 修饰的常函数和普通成员函数构成重载(以后讲到)

(3)重载匹配的原则:

完全匹配 > 常量转换 > 升级转换 > 标准转换 > 自定义类型转换(以后讲到) > 省略匹配

(4) 函数重载的原理:

a.C++编译器通过对函数进行换名,将参数表信息体现在新的函数名中,从而实现重载
如:

void show(int i,int j){} 
=> _Z4showii; 换名之后的新名字 
void show(int j,int i) 
=> _Z4showii;

b.C 程序也可以通过 C++编译器换名后的新函数名调用 C++模块中的函数

c.通过 extern “C” 关键字可以明确要求 C++编译器不要对函数进行换名的操作,以满 足 C 程序可以直接调用 C++模块中的函数

7.2 缺省参数:

函数的参数有缺省值,也就是默认值:

void foo(int i,char c = 'A',char* p = NULL) {...}

foo(66,'B',"hello"); 
foo(66,'B'); // p = NULL; 
foo(66); // c = 'A',p = NULL

注意:
(1)缺省参数必须靠右。如果某一个参数带有缺省值,那么该参数右边的所有参数都必须 有缺省值
如:

void foo(int i,char c = 'A',char* p){} // error 
foo(66,"hello");

(2)如果函数的声明和定义分开,那么缺省参数的值只能写在函数的声明部分
如:

void foo(int i,char c = 'A',char* p = NULL);
void foo(int i,char c,char* p){}

(3)注意防止由于缺省参数而引发的重载冲突问题

扩展:
(1)void fn(){}; 在 C 语言中表示可以接受任意多个任意类型的实参;在 C++中表示不接 受任何实参
(2)在 C 语言中可以不对函数进行声明,会自动做隐式声明;在 C++中调用函数之前必须 对所调用的函数进行声明,或者将被调用函数的定义放在调用函数之前

7.3 哑元:

只有数据类型没有名称的参数叫哑元
如:

void fn(int){} 
fn(); //error 
fn(66); // ok

用途:
(1)为了兼容以前的代码
(2)用于运算符重载,主要用于区分前后缀自增减运算符(以后讲到)

7.4 内联:

使用 inline 关键字修饰的函数叫做内联函数
类似于 C 语言中的宏函数,可以进行指令的替换,相对于宏函数有一定的优势,可以检 查数据类型,可以计算表达式的值等等

注意:
inline 关键字修饰函数,仅仅表示这是一种建议而不是要求,所有使用 inline 关键字 修饰的函数不一定会做内联的处理;反之,没有使用 inline 关键字修饰的函数也可能根据 编译器的优化策略进行内联处理

练习:
自定义一个计算 int 类型参数平方的函数,并且通过返回值返回计算的结果,分别使用 inline 修饰和不修饰去观察是否内联

扩展:

(1)多次调用的小而简单的函数适合内联
(2)调用次数极少并且大而复杂的函数不适合内联
(3)递归函数无法内联

你可能感兴趣的:(C++和Qt基础开发,c++,程序设计,编程语言)