一、结构化:C语言编程
C语言是一种结构化语言。它层次清晰,便于按模块化方式组织程序,易于调试和维护。C语言的表现能力和处理能力极强。它不仅具有丰富的运算符和数据类型,便于实现各类复杂的数据结构。它还可以直接访问内存的物理地址,进行位(bit)一级的操作。
[A]. 简洁紧凑、灵活方便
C语言一共只有32个关键字,9种控制语句,程序书写自由,主要用小写字母表示。它把高级语言的基本结构和语句与低级语言的实用性结合起来。 C 语言可以象汇编语言一样对位、字节和地址进行操作, 而这三者是计算机最基本的工作单元。
◆ 位结构定义
#pack(1)
struct TDate
{
int year:7 //0-128
int month:4 //0-16
int day:5 //0-32
}
#pack ()
上面的结构year占用结构的7bit大小,sizeof(TDate)=16;
◆ 字节对齐
⑴ 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
⑵ 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);
⑶ 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
【1】为什么要进行字节对齐?
效率问题,对于未对齐的成员编译器要进行两次访问才能取到真正的值,如TDate中的month,因为边界在两个对齐域中,所以取值要进行两次访问,所以一般情况会定义成员year:8,month:8,day:8,除非有结构大小要求。
[B]. 运算符丰富
C的运算符包含的范围很广泛,共有种34个运算符。C语言把括号、赋值、强制类型转换等都作为运算符处理。从而使C的运算类型极其丰富表达式类型多样化,灵活使用各种运算符可以实现在其它高级语言中难以实现的运算。
◆ 传统的C方式位操作:
⑴ 基本操作:使用一个unsigned int变量来作为位容器。
⑵ 操作符:
[ | ] 按位或操作符:result=exp1|exp2;当exp1和exp2中对应位中至少有一个为1时,result中对应位为1,否则为0。
[ & ] 按位与操作符::result=exp1&exp2;当exp1和exp2中对应位全为1时,result中对应位为1,否则为0。
[ ^ ] 按位异或或操作符:result=exp1^exp2;当exp1和exp2中对应位不相同时,result中对应位为1,否则为0。
[ ~ ] 反转操作符:将位容器中的所有位都反转,1变为0,0变为1。
[ << ] 按位左移操作符:exp<<n,将容器中所有的位向左移n位,空出的位用0填充。
[ >> ] 按位右移操作符:exp>>n,将容器中所有的位向右移n位,空出的位用0填充。
[ |=、&=、^= ] 分别对应[ |、&、^ ]三种操作符的复合操作符。
◆ C++中的bitset容器
⑴ 头文件:#include <bitset>
⑵ 声明一个容器:
(a)声明一个指定位数的空容器(所有位设为0): bitset<int> bits;
(b)声明一个指定位数并将指定的几个位初始化为相应值的容器: bitset<n> bits(int);
bitdet<int> bits(string&)
bitset模板类中类型参数传递容器的位数,而构造函数参数通过一个int或一个string&值来从右至左初始化容器中的相应值。
⑶ bitset的基本用法:
⑷ bitset与传统C位操作及字符串的转换
可以通过to_string()成员将容器转输出为一个string字符串,另外还可以用to_long()成员将容器输出到传统的用于C风格的位容器中。如:
unsigned long bits = bits.to_long();
sting str(bits.to_string());
⑸ bitset支持所有的位操作符。
[C]. 数据结构丰富
C的数据类型有:整型、实型、字符型、数组类型、指针类型、结构体类型、共用体类型等。能用来实现各种复杂的数据类型的运算。并引入了指针概念,使程序效率更高。另外C语言具有强大的图形功能, 支持多种显示器和驱动器。且计算功能、逻辑判断功能强大。
[D]. C是结构式语言
结构式语言的显著特点是代码及数据的分隔化,即程序的各个部分除了必要的信息交流外彼此独立。这种结构化方式可使程序层次清晰,便于使用、维护以及调试。C语言是以函数形式提供给用户的,这些函数可方便的调用,并具有多种循环、条件语句控制程序流向,从而使程序完全结构化。
[E]. C语法限制不太严格、程序设计自由度大
一般的高级语言语法检查比较严,能够检查出几乎所有的语法错误。而C语言允许程序编写者有较大的自由度。
[F]. C语言允许直接访问物理地址,可以直接对硬件进行操作
因此既具有高级语言的功能,又具有低级语言的许多功能,能够象汇编语言一样对位、字节和地址进行操作,而这三者是计算机最基本的工作单元,可以用来写系统软件。
[G]. C语言程序生成代码质量高,程序执行效率高
一般只比汇编程序生成的目标代码效率低10へ20%。
[H]. C语言适用范围大,可移植性好
C语言有一个突出的优点就是适合于多种操作系统, 如DOS、UNIX,也适用于多种机型。
当然,C语言也有自身的不足,比如:C语言的语法限制不太严格,对变量的类型约束不严格,影响程序的安全性,对数族下标越界不作检查等。从应用的角度,C语言比其他高级语言较难掌握。
总之,C语言既有高级语言的特点,又具有汇编语言的特点;既是一个成功的系统设计语言,有时一个使用的程序设计语言;既能用来编写不依赖计算机硬件的应用程序,又能用来编写各种系统程序;是一种受欢迎、应用广泛的程序设计语言。
二、对象化,模块化:C++编程
[A]. 模板类
定义模块类的注意事项,在进行模板类编程时,往往为了避免一全局变量的重复定义而将实现与声明分离,而此时定义模板类需要遵循一些规则:
1. 将C++模板类的声明和定义都放在一个文件,如.h或.cpp文件中,使用的时候加入#include "模板类文件名.h(或.cpp) "即可。
2. 将C++模板类的声明和定义分别放在.h和.cpp文件中,且在.cpp文件中包含 #include ".h"
不过在使用时,会因为不同的开发环境而有所不同:
a. 在集成开发环境code::blocks下
在调用程序中只加入 #include "模板类.cpp" 可以编译、运行通过,或者同时加入 #include "模板类.h" 和 "模板类.cpp" 也可以编译、运行通过;
但只加入 #include "模板类.h" 是不能够运行通过,会出现 undefined reference to 错误
b. 在linux gcc 环境下:
在调用程序中只能加入 #include "模板类.cpp" 才能编译、运行通过;
否则,如果同时加入 #include "模板类.h" 和 "模板类.cpp" 则出现 class 重复定义的错误
【1】为什么需要在调用程序中加入 #include "模板类.cpp" ?
因为只有将模板类.cpp文件同调用程序.cpp文件放在一起编译、运行才能真正确定类的真正类型,才能运行通过,不出现link之类(undefined reference to)的错误
【2】为什么要将类的声明和定义分别放在不同的文件中?
如果实现中需要定义全局变量,多次引用该文件将导致变量重复定义,即使使用预编译命令也不能解决问题。
[B]. 友元类,友元模板类
1. 声明方式:
a. 友元函数:friend ret-type classname::funname(....);
b. 友元类:friend class classname;
唯一要注意的就是不管是友元函数还是友元类,定义友元关系前必须先声明
2. 友元关系:
C中声明A是其友元类,那么最基本的就是A可以使用C中的private方法或者对象。
A是B的基类,C是D的基类。ABCD中就有如下关系:
a. B新增的方法不能访问C的私有成员
b. B从A继承而来的方法可以访问C的私有成员
c. A只能访问D中从C中继承而来的私有成员,D中新增的私有成员不能访问!
(1)友元关系不可以继承,但对已有的方法来说访问权限不改变;
(2)如果改写基类的方法则访问权限改变;
(3)友元关系不具有传递性;
若类B是类A的友元,类C是B的友元,类C不一定是类A的友元。
定义方法:
template <typename T>
class Node
{
template <typename T> friend class ListNode;
//友元模板类的声明,这种写法friend class ListNode<T>;
private:
T data;
Node<T> *next;
//模板函数变量的定义一定要定义参数列表
};
【1】为什么要使用友元类?
可以访问类的私有成员,笼统的说法就是这样,很多细节方面需要使用友元类,如实现将成员函数定义回调函数;
【2】typename的作用是什么?
typename和class允许模板声明时使用一个未定义的参数类型,在定义时实例化;
·在声明 template parameters(模板参数)时,class 和 typename 是可互换的。
·用 typename 去标识 nested dependent type names(嵌套依赖类型名),在 base class lists(基类列表)中或在一个 member initialization list(成员初始化列表)中作为一个 base class identifier(基类标识符)时除外。
1. 什么是友元函数?
一个类的私有数据成员通常只能由类的函数成员来访问,而友元函数可以访问类的私有数据成员,也能访问其保护成员
2. 友元函数的用处体现在哪里?
2.1 使用友元函数可提高性能,如:用友元函数重载操作符和生成迭代器类
2.2 用友元函数可以访问两个或多个类的私有数据,较其它方法使人们更容易理解程序的逻辑关系
3. 使用友元函数前应注意:
3.1 类的友元函数在类作用域之外定义,但可以访问类的私有和保护成员
3.2 尽管类定义中有友元函数原型,友元函数仍然不是成员函数
3.3 由于友元函数不是任何类的成员函数,所以不能用句柄(对象)加点操作符来调用
3.4 public, private, protected成员访问符与友员关系的声明无关,因此友元关系声明可在类定义的任何位置,习惯上在类定义的开始位置
3.5 友元关系是指定的,不是获取的,如果让类B成为类A的友元类,类A必须显式声明类B为自己的友元类
3.6 友元关系不满足对称性和传递性
3.7 如果一个友元函数想与两个或更多类成为友元关系,在每个类中都必须声明为友元函数
4. 注:由于C++属于混合语言,常在同一个程序中采用两种函数调用且这两种函数调用往往是相反的。类C语言的调用将基本数据或对象传递给函数,C++调用则是将函数(或信息)传递给对象。