知识屋:更实用的电脑技术知识网站
所在位置:首页 > 教育

C++程序设计(面向对象进阶)

发表时间:2022-03-25来源:网络

课程网址:link - 北京邮电大学 - 崔毅东

C++概览

C++编程范式

Structural Programming (结构化编程)Object-Oriented Programming (OOP,面向对象编程)Generic Programming (GP,泛型编程)Functional Programming (FP,函数式编程)

高级语言的演化

C语法的增强及对应的C++11特性

引用(Reference)

引用类型做函数的参数:引用传递
You can use a reference variable as a parameter in a function and pass a regular variable to invoke the function. (引用可做函数参数,但调用时只需传普通变量即可)
When you change the value through the reference variable, the original value is actually changed. (在被调函数中改变引用变量的值,则改变的是实参的值)

下面的案例分别用普通变量、指针和引用三种形式来调用实参:
可以看到第一种,在调用函数时实参的值传递给形参,但实参在调用后不发生改变。
而第二种和第三种,在调用函数时实则对实参所在内存地址中存的值进行了改变。
(引用可以简单理解为const指针,一旦初始化就无法再绑定到其他变量上)

空指针(nullptr)

0带来的二义性问题

C++03中,空指针使用“0”来表示。0既是一个常量整数,也是一个常量空指针。C语言中,空指针使用(void *)0来表示。有时候,用“NULL”来表示空指针(一种可能的实现方式是#define NULL 0)。

C++标准化委员会希望“空指针”是一个确定的东西。
C++11中引入保留字“nullptr”作为空指针。

动态内存管理:分配/释放(Dynamic memory management: Allocate/Release)

C++中通过运算符new申请动态内存

new (初值) ; //申请一个变量的空间
new [常量表达式] ; //申请数组

如果申请成功,返回指定类型内存的地址;
如果申请失败,抛出异常,或者返回空指针(nullptr)。(C++11)

动态内存使用完毕后,要用delete运算符来释放

delete ; //删除一个变量/对象
delete [] ; //删除数组空间

布尔数据类型(Boolean data type)

直接输出布尔类型变量会输出结果0或1。
用std::boolalpha输出布尔类型变量会输出结果false或true(用字符形式输出)。

列表初始化(List Initialization)

C++11标准之前的初始化方法

int x = 0; int y(2); char c('a'); int arr[] = { 1,2,3 }; char s[] = "Hello";

C++11标准仍然支持旧的初始化方法。

列表初始化

列表初始化是C++11的一个新特性,“列表”是用花括号括起来的一些值。

列表初始化的两个分类

Direct list initialization (直接列表初始化)Copy list initialization (拷贝列表初始化)//直接列表初始化 /* Variable initialization */ int x{}; // x is 0; int y{ 1 }; // y is 1; /* Array initialization */ int array1[]{ 1,2,3 }; char s1[ 3 ] { 'o', 'k' }; char s3[]{ "Hello" }; //拷贝列表初始化 /* Variable initialization */ int z = { 2 }; /* Array initialization */ int array2[] = { 4,5,6 }; char s2[] = { 'y','e','s' }; char s4[] = { "World" }; char s5[] = "Aloha"; // Omit curly braces (省略花括号)

在能使用列表初始化的地方优先使用列表初始化,因为当发生隐式类型转换丢失精度的时候(窄化narrowing),列表初始化会编译出错进行提示。

如:int x { 2.5 };

类型转换(Type conversion)

C风格强制类型转换

语法:(type) value

printf("%d", (int) 2.5);

C++风格强制类型转换

语法:static_cast< type > value

cout (1) / 2;

C++11 对类型系统的增强(C++11 Enhancement for Type System)

类型(Type)是贯穿于计算机程序中的概念

数据类型 (Data type)
int, long int, double,
struct, char *, float [], int (*f)()…

计算机程序构造块(Constructs of a Computer Program)
计算机程序构造块是不同大小粒度的计算机程序组成部分,它包括变量、表达式、函数或者模块等。

什么是类型系统(What is Type System)

在编程语言中,“类型系统”是将“type”属性指定给不同计算机程序构造块的规则集。

这些类型规范并强制程序员用于数据结构和组件的其它隐式类别(e.g. “string”, “array of float”, “function returning boolean”)。

为什么使用类型系统(Why using Type System)

类型系统可以减少程序中可能出现的bug。

类型系统减少BUG的方法是:

定义不同程序块间的接口检查多个块之间是否以一致的方式连接在一起

静态类型 v.s. 动态类型

程序设计语言的类型系统机制会检查连接在一起的多个块的一致性。

上述检查若发生在编译期,称为静态类型 (如C、C++、Java等编译语言)。
上述检查若发生在运行时,称为动态类型 (如Python等脚本语言)。
上述检查若同时存在于编译期和运行时,称为混合类型。

自动类型推导:auto关键字(Automatic Type Deduction: auto)

关键字 auto

C++03及之前的标准中,auto放在变量声明之前,声明变量的存储策略。但是这个关键字常省略不写。
C++11中,auto关键字放在变量之前,作用是在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型。

auto的使用限制

auto 变量必须在定义时初始化,这类似于const关键字auto a1 = 10; //正确 auto b1; //错误,编译器无法推导b1的类型 b1 = 10; 定义在一个auto序列的变量必须始终推导成同一类型auto a4 = 10, a5{20}; //正确 auto b4{10}, b5 = 20.0; //错误,没有推导为同一类型 如果初始化表达式是引用或const,则去除引用或const语义。int a{10}; int &b = a; auto c = b; //c的类型为int而非int&(去除引用) const int a1{10}; auto b1 = a1; //b1的类型为int而非const int(去除const) 如果auto关键字带上&号,则不去除引用或const语意int a = 10; int& b = a; auto& d = b;//此时d的类型才为int& const int a2 = 10; auto& b2 = a2;//因为auto带上&,故不去除const,b2类型为const in 初始化表达式为数组时,auto关键字推导类型为指针。int a3[3] = { 1, 2, 3 }; auto b3 = a3; cout return 10; } auto fun2() { return 'g'; } // C++14 int main(){ // Data type of x is same as return type of fun1() // and type of y is same as return type of fun2() decltype(fun1()) x; // 不会执行fun1()函数 decltype(fun2()) y = fun2(); cout return (a > b ? a : b); } // Calling (调用内联函数) int x = max (3, 5); int y = max (0, 8); // Inline expansion(内联展开) int x = (3 > 5 ? 3 : 5); int y = (0 > 8 ? 0 : 8);

内联函数的使用

编译器在遇到内联函数的调用时,会将内联函数的函数体展开到调用位置,从而避免函数调用的开销。

一般来说,内联函数只有在需要考虑程序运行性能的环境中才使用。

程序员所用的 inline 关键字,只是对编译器的一个请求。内联函数是否展开,是由编译器决定的。

将内联函数的声明和定义分离

在C++标准7.1.2.4节有如下说明

An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case (3.2). [ Note: A call to the inline function may be encountered before its definition appears in the translation unit. —end note ]

内联函数应在每个翻译单元中定义。在该翻译单元中它遵循“单一定义规则(ODR)”,并且所有该内联函数定义必须完全相同。[注释:在翻译单元中可能会在内联函数定义出现之前就有调用该内联函数的语句]

因此,内联函数声明和定义分类的用法如下:

#include inline void foo(); int main() { foo(); } inline void foo() { std::cout s { “Hello”, “World”, “!”};

用法

想要操作某个广义集合中的所有元素,那么只需要关心:

从集合中取出某个元素保证所有元素都被遍历

例:把数组a的元素都输出到屏幕上,然后把数组的元素翻倍。

int a[] = { 2,1,4,3,5 }; for (auto i : a) { std::cout
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜