1. 命名规范 2. 代码格式 3. QString的判断 4. 对象的判空 5. 隐式接口&显式接口 6. vector&string 7. static 8. const 9. volatile 10. for&while 11. register 12. extern 13. struct 14. explicit 15. typedef&using
命名规范
类命名规范:首字母大写,和本程序密切相关的类(非可重用类),类名前要加上一个特定的大写字母(初步决定为此程序名的第一个字母),同QT官方类的命名方式
函数命名规范:使用驼峰命名法,即首字母小写,后面的每个单词的首字母大写,例如:void openFile();
枚举命名规范:枚举本身名称所有单词首字母大写,枚举常量的名字应该含有枚举类型的信息,因为枚举类型可以被直接使用,如果名字过于简单,可能会导致歧义
变量命名规范:每行一个变量,尽可能避免短的变量名,等到真正需要使用时再定义变量,普通成员变量使用驼峰命名法,静态数据成员以s_开头,例如s_Singleton
类成员变量以m_开头,属性对应的变量一律使用m_开头,后面跟驼峰命名法,临时变量使用全小写加下划线命名方式,例如:window_width
对无特殊意义的临时变量可使用ijz命名
结构体命名规范:结构体本身名称所有单词首字母大写,结构体成员变量使用驼峰命名法,另外考虑到结构体字节对齐问题,定义时相同类型成员定义在一起,并且,所占字节数多的在前
代码格式
头文件的格式:不算头文件,在类的声明中将Q_ENUMS Q_FLAGS的使用放在最前面,属性的定义紧跟其后,再然后是构造函数的修饰符及其定义,析构函数紧跟其后,修饰符之前不加
任何空白符
成员函数及成员变量的定义的排列顺序为:public 成员函数,信号,槽函数,protect的成员函数,槽函数,成员变量,private的成员函数,槽函数,成员变量
QString的判断
QString().isNull; //return true
QString().isEmpty(); //return true
QString("").isNull(); //return false
QString("").isEmpty(); //return true
QString("abc").isNull(); //return false
QString("abc").isEmpty(); //return false
对象的判空
对象不需要判空,对象就是类的实例化,构造函数中是不能抛出异常的,因为假如没有成功构造,却抛出异常,那么仍会调用析构函数,
可以想象,一个对象都没有构造成功,它又怎么能析构呢,对象虽然不能判空,但是对象指针可以判断是否为空
隐式接口&显示接口
隐式接口:隐式实现接口时,接口和类(实现接口的类)都可以访问类中的方法
显示接口:只有通过接口来访问类中的方法
举例:定义一个接口 public Interface ICategory {
string Name();
}
隐式实现 public class Category:ICategory {
public string GetName() {
return name;
}
}
显示实现 public class Category:ICategory {
public string ICategory.GetName() {
return name;
}
}
隐式实现接口时,我们有两种方式调用实现接口的方法(GetName())
1. ICategory category = new Category();
category.GetName();
2. Category category = new Category();
category.GetName();
显示实现接口时,我们只有一种方法来调用
1. ICategory category = new Category();
category.GetName();
vector&string
string对象是一个可变长的字符序列;vector对象一组同类型对象的容器,意在代替数组,vector可以记忆大小,迭代器允许对容器中的对象进行间接访问,对于string对象和vector对象来说
可以通过迭代器访问元素或者在元素间访问,如果可能,应该尽量避免使用C++内置数组和字符串,标准的vector类和string类在实现的时候隐藏了内置的C风格的数组和指针的操作,
缓冲区溢出:即buffer overflow,一种严重的程序故障,主要原因是试图通过一个越界的索引访问容器内容,容器类型包括string,vector和数组等
vector,容器的用法,vector<string> v; //只装string对象的vector,如果试图加入其他类型,编译器会给错误提示信息,vector提供了push_back,insert()等函数
string, string line;
static
1. 静态全局变量:限定作用域在本文件中即其他文件不可见,并且可以在其他文件中声明同名全局变量而不冲突
2. 静态局部变量:改变变量的存储方式,延长变量的生命周期,函数每次被调用,普通局部变量都是重新分配,而静态局部变量保持上次调用的值不变
//静态变量通性:保存在静态数据区,默认初始化为0,只初始化一次,与全局变量很像
3. C++中的静态变量,在类中声明,类外定义即初始化(因为C++中的静态变量是与类是同级的),定义了静态对象的函数不能作为内联函数(内联的特性是展开,那么就会发生多次定义)
const static变量可以在类中定义并初始化,因为const变量是不可变,因此在定义时需要初始化一次
4. C++中的静态函数只能访问静态变量,静态函数在内存中只有一份,静态函数不能被其他文件使用,其他文件可以定义相同名字的函数,普通函数在每个调用中维持一份拷贝
const
本质:const在谁后面谁就不可修改,const在最前面则将其后移一位即可,二者等效,*号也算一种数据类型,const意味着只读,在能使用const的地方尽量使用const,
任何不会修改数据成员的函数都应该声明为const类型,const int buffsize = 512;编译器将在编译过程中将buffsize都替换成512
举例: 1. const int a:与int const a同义,此时a是一个常整型数
2. const int *a:此时a是一个指向常整型数的指针,即指向的整型数不可修改,但指针可以
3. int * const a:此时a是一个指向整型数的常指针,即指向的整型数可以修改,但指针不可修改
4. int const *a const:此时a是一个指向常整型的常指针,即指向的整型数与指针都不可以修改
//小技巧:如果关键字出现在*左边,表示被指物是常量;如果出现在*右边,表示指针自身是常量;如果出现在*两边,表示被指物与指针本身都是常量
5. const变量定义时必须初始化(C++),一般变量定义时不一定要初始化,变量在定义时被分配内存,const修饰数组时必须分配内存
6. 如果函数的返回值不能被修改,那么需要在函数的声明里加const,函数声明时也要用const修饰
volatile
提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据,需要注意的是,没有volatile也可能
能正常运行,但是可能修改了编译器的优化级别后又不能正常运行了,因此经常出现debug版本正常,但是release版本却不能正常的问题。所以为了安全起见,只要是等待别的程序
修改某个变量的话,就加上volatile关键字,此外多线程操作也要考虑使用volatile
for&while
while:1. 用于不确定要迭代多少次时 2. 想在循环结束后访问循环控制变量 3. 在while循环中创建的变量在每一次的循环中都会经历创建与销毁的过程
例子:vector<int> v;
int i;
while(cin>>i)
v.push_back(i);
auto beg = v.begin();
while (beg != v.end() && *beg >= 0)
++beg;
if (beg == v.end())
/此时可以在第二个循环结束后访问auto beg,仍然可以使用beg的值进行其他处理
for:形如 for(init-statement; condition; expression)
statement; //可以是一条语句也可以是一条复合语句
for语句中定义的变量只在for循环内有效,初始化语句可以定义多个对象,但是只能有一个声明语句,因此所有所有变量的基础类型必须相同,
如 int i = 3,j = 4;
for语句头的一个或全部语句都可以被省略,即一个单独的分号代表的是一个空语句,for(;;;)即代表无限循环,相当于while(1)
初始化部分省略为;(分号)时表示没有什么要被初始化,即所有的初始化工作都已经在前面完成,
条件部分省略等价于在条件部分写了一个true,此时循环体内需要有语句负责退出循环,否则将无限循环
表达式部分省略即表示一次循环结束后不对变量做什么操作,或者操作在statement部分完成
register
寄存器是cpu的一部分,是计算机中速度最快的存储器,分为通用寄存器,专用寄存器,段寄存器,其他寄存器,每个寄存器存储一种类型的数据
register int a;定义,使用register存储类型的目的一般是为了提高执行速度,但是register只是向编译器提出的建议,并不是强制要求
extern
引用在别的源文件中定义的全局变量或函数(前提是全局变量和函数不是静态的),提示编译器遇到此变量和函数时在其他模块中寻找其定义
使用背景:在源文件里定义的函数或全局变量是不能直接就被其他源文件引用的,
使用extern引用的全局变量最后在是源文件中定义而不是头文件,为了减少文件之间的编译依赖,能包不含头文件就不包含头文件
使用extern引用其他源文件中定义的全局变量或函数时,需要与原定义保持一致,例如原定义是数组,那么extern修饰时就不能是指针形式,
要严格对应声明时的形式
struct
定义:表示结构体,通俗讲就是打包封装,把一些有共同特征的变量封装在内部,通过一定方法访问修改内部变量
第一种:只有结构体定义
struct stuff {
char job[20];
int age;
float height;
}; //注意分号不可少
第二种:附加该结构体类型的"结构体变量"的初始化的结构体定义
struct stuff {
char job[20];
int age;
float height;
}zhangkunwu; //即是相当于第一种加 struct stuff zhangkunwu;
空结构体的大小为1,不为0,这就是实例化的原因,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个
空类或空结构体(C++中结构体也可看做类)隐含的加一个字节,这样空类或空结构体在实例化后就可以在内存中得到一个独一无二的地址
C++中结构体与class的唯一区别在于默认的访问权限不同,struct默认是public,而class默认是private,出于统一编程的考虑,建议当我们希望定义的类的所有成员都是public时
使用struct,反之使用class
explicit
修饰的函数是禁止隐式转换的,例如在构造函数声明中加入关键字explicit,声明时需要加,定义时就不需要再加explicit了,explicit 也只能用于构造函数
typedef&using
typedef double wages;//wages是double的同义词
typedef wages base,*p;//base是double的同义词,p是double*的同义词
关键字typedef,typedef作为声明语句中的基本数据类型的一部分出现,含有typedef的声明语句定义的不再是变量而是类型别名,
using:新标准的一种方法,别名声明,使用别名声明来定义类型的别名
using SI = Sales_item;//SI是Sales_item的同义词
这种方法用关键字using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名
类型别名和类型等价,只要是类型的名字能出现的地方,类型别名都可以使用