c++风格
qtcreator必须掌握的快捷键
1.ctrl+tab切换打开的窗口
2.alt+enter在.cpp里面快速添加定义
3.ctrl+shift 修改相同变量
4.ctrl+m书签,ctrl+.转到书签
5.ctrl+e+2/3/1分栏显示
6.f4/f2/ctrl+shift+up(down)/ctrl+i
头文件
- 自给自足原则
用户和重构工具不需要为特别场合而包含额外的头文件。
- #define保护
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...
#endif // FOO_BAR_BAZ_H
- 尽量避免前置声明
waht is 前置声明?
class Date
{
private:
int year, month, day;
};
//if want to use this class ,have two ways:
//one前置声明
class Date;
class Task1
{
public:
Date getData();
};
//two包含头文件
#include "Date.h"
class Task2
{
public:
Date getData();
};
- 慎用内联函数
在函数很短,可以内联,但是得保证此函数很少被调用
- include的路径和顺序
#include <zylg.h>// find it on system first
#include "zylg.h"//find it on project first
作用域
#ifndef MYTEST_H
#define MYTEST_H
#include<iostream>
const int i=5;//内链接的特性,可以让其他的文件重新定义i(假如其他的问价include这个文件,当然也可以直接使用)
namespace zylg
{
void s();
namespace//让其具有内部链接性,相当于static后的一大块区域
{
void s1(){
std::cout<<"my is inline namespace function,as in static area,\n other file don`t use me\n";}
}
};
#endif // MYTEST_H
#include<iostream>
using namespace std;
int i=9;
void s1()
{
cout<<"how are you";
}
int main(int argc, char *argv[])
{
s1();
return 0;
}
1.匿名的命名空间会把空间里面的定义的东西自动放在上一级命名空间,比如上述代码可以zylg::s1(),这样保证了全局变量的名称资源(因为具有内部链接性),同时节约了命名空间数量
2.局部变量
将函数变量尽可能至于最小的作用域3.全局变量和静态变量尽可能在控制范围内,少用
类
1.不要在构造函数里面调用虚函数,也不要在无法报出错误时进行可能失败的初始化.
2.不要定义隐式类型转换. 对于转换运算符和单参数构造函数, 请使用 explicit 关键字.别让int默默的就double了,explicit可以保证函数不会发生隐式转换,涉及类型转换的应该加上
3.可拷贝类型和可移动类型
如果你的类型需要, 就让它们支持拷贝 / 移动. 否则, 就把隐式产生的拷贝和移动函数禁用.
// MyClass is neither copyable nor movable.
MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;
4.结构体
仅当只有数据成员时使用 struct, 其它一概使用 class.
继承
使用组合 (YuleFox 注: 这一点也是 GoF 在 <> 里反复强调的) 常常比使用继承更合理. 如果使用继承的话, 定义为 public 继承.
//介绍组合模式
class component
{
//声明全部你所要用到的函数,在此处为虚函数,不去定义
}
class composite:public component
{
//实现虚函数全部
}
class left:public component
{
//实现个别的虚函数
}
/*
*在继承的时候,析构函数声明为虚函数,不然会发生内存泄露
*/
6.多重继承
真正需要用到多重实现继承的情况少之又少. 只在以下情况我们才允许多重继承: 最多只有一个基类是非抽象类; 其它基类都是以 Interface 为后缀的 纯接口类.
7.接口
接口是指满足特定条件的类, 这些类以 Interface 为后缀 (不强制).
8.运算符重载
除少数特定环境外, 不要重载运算符. 也不要创建用户定义字面量.
9.存取控制
将 所有 数据成员声明为 private, 除非是 static const 类型成员 (遵循 常量命名规则). 处于技术上的原因, 在使用 Google Test 时我们允许测试固件类中的数据成员为 protected.
10.声明顺序
类定义一般应以 public: 开始, 后跟 protected:, 最后是 private:. 省略空部分.
函数
1.函数参数顺序
函数的参数顺序为: 输入参数在先, 后跟输出参数.
- 编写简短函数,我们倾向于编写简短, 凝练的函数.
3.引用参数
所有按引用传递的参数必须加上 const.
as:void Foo(const string &in, string *out);
4.函数重载
若要使用函数重载, 则必须能让读者一看调用点就胸有成竹, 而不用花心思猜测调用的重载函数到底是哪一种. 这一规则也适用于构造函数.
5.只允许在非虚函数中使用缺省参数, 且必须保证缺省参数的值始终一致. 缺省参数与 函数重载 遵循同样的规则. 一般情况下建议使用函数重载, 尤其是在缺省函数带来的可读性提升不能弥补下文中所提到的缺点的情况下.
study for google
1.所有权与智能指针,动态分配出的对象最好有单一且固定的所有主, 并通过智能指针传递所有权.
所有权是一种登记/管理动态内存和其它资源的技术. 动态分配对象的所有主是一个对象或函数, 后者负责确保当前者无用时就自动销毁前者. 所有权有时可以共享, 此时就由最后一个所有主来负责销毁它. 甚至也可以不用共享, 在代码中直接把所有权传递给其它对象.
智能指针是一个通过重载 * 和 -> 运算符以表现得如指针一样的类. 智能指针类型被用来自动化所有权的登记工作, 来确保执行销毁义务到位. std::unique_ptr 是 C++11 新推出的一种智能指针类型, 用来表示动态分配出的对象的独一无二的所有权; 当 std::unique_ptr 离开作用域时, 对象就会被销毁. std::unique_ptr 不能被复制, 但可以把它移动(move)给新所有主. std::shared_ptr 同样表示动态分配对象的所有权, 但可以被共享, 也可以被复制; 对象的所有权由所有复制者共同拥有, 最后一个复制者被销毁时, 对象也会随着被销毁.
2.cppplint
使用 cpplint.py 检查风格错误.
else study
1.所有按引用传递的参数必须加上const.
2.只在定义移动构造函数与移动赋值操作时使用右值引用. 不要使std::forward.
3.若要用好函数重载,最好能让读者一看调用点(call site)就胸有成竹,不用花心思猜测调用的重载函数到底是哪一种。该规则适用于构造函数。
4.我们不允许使用缺省函数参数,少数极端情况除外。尽可能改用函数重载。
5.我们不允许使用变长数组alloca().
6.我们允许合理的使用友元类及友元函数.
7.我们不使用 C++ 异常.
8.我们禁止使用 RTTI.在运行时判断类型通常意味着设计问题. 如果你需要在运行期间确定一个对象的类型, 这通常说明你需要考虑重新设计你的类
9.使用 C++ 的类型转换, 如 static_cast<>(). 不要使用 int y = (int)x 或 int y = int(x) 等转换方式;
10.只在记录日志时使用流.不要使用流,除非是日志接口需要. 使用 printf 之类的代替.使用流还有很多利弊, 但代码一致性胜过一切. 不要在代码中使用流.
11.对于迭代器和其他模板对象使用前缀形式 (++i) 的自增, 自减运算符.
12.我们强烈建议你在任何可能的情况下都要使用 const. 此外有时改用 C++11 推出的 constexpr 更好。
13.整形int16_t.如果您的变量可能不小于 2^31 (2GiB), 就用 64 位变量比如 int64_t. 此外要留意,哪怕您的值并不会超出 int 所能够表示的范围,在计算过程中也可能会溢出。所以拿不准时,干脆用更大的类型。
14.可移植性,代码应该对 64 位和 32 位系统友好. 处理打印, 比较, 结构体对齐时应切记
15.使用宏时要非常谨慎, 尽量以内联函数, 枚举和常量代替之.
16.nullptr 和 NULL,整数用 0, 实数用 0.0, 指针用 nullptr 或 NULL, 字符 (串) 用 '\0'.
17.尽可能用 sizeof(varname) 代替 sizeof(type).
18.用 auto 绕过烦琐的类型名,只要可读性好就继续用,别用在局部变量之外的地方。
19.适当使用 lambda 表达式。别用默认 lambda 捕获,所有捕获都要显式写出来。
20.只使用 Boost 中被认可的库.
命名规则
函数命名, 变量命名, 文件命名要有描述性; 少用缩写.
//文件命名:文件名要全部小写, 可以包含下划线 (_) 或连字符 (-), 依照项目的约定. 如果没有约定, 那么 “_” 更好.
//类型名命名:类型名称的每个单词首字母均大写, 不包含下划线
//变量名:变量 (包括函数参数) 和数据成员名一律小写, 单词之间用下划线连接,类变量以下划线结尾
//常量名:声明为 constexpr 或 const 的变量, 或在程序运行期间其值始终保持不变的, 命名时以 “k” 开头, 大小写混合
//函数名;规函数使用大小写混合, 取值和设值函数则要求与变量名匹配
//命名空间:命名空间以小写字母命名. 最高级命名空间的名字取决于项目名称
//枚举;枚举的命名应当和 常量 或 宏 一致: kEnumName 或是 ENUM_NAME.
注释
使用 // 或 /* */, 统一就好.
在每一个文件开头加入版权公告.描述了该文件的内容
每个类的定义都要附带一份注释, 描述类的功能和用法, 除非它的功能相当明显.
通常变量名本身足以很好说明变量用途. 某些情况下, 也需要额外的注释说明.
//注:注释别写一些谁看函数都能看出来的废话,不如不写
格式
//1.每一行代码字符数不超过 80.
//2.尽量不使用非 ASCII 字符, 使用时必须使用 UTF-8 编码.
//3.倾向于不在圆括号内使用空格. 关键字 if 和 else 另起一行.
//4.switch 语句可以使用大括号分段, 以表明 cases 之间不是连在一起的. 在单语句循环里, 括号可用可不用. 空循环体应使用 {} 或 continue.
//5.不要在 return 表达式里加上非必须的圆括号.
//6.访问控制块的声明依次序是 //7.public:, protected:, private:, 每个都缩进 1 个空格.
//8.命名空间内容不缩进.
pro文件详解
TAMPLATE
描述为建立目标文件而采用的模板,即生成何种makefile文件
a.app(应用程序)
b.lib(库文件)
c.subdirs(子工程)
d.vcapp(仅用于windows的应用程序)
e.vclib
HEADERS
所有头文件列表
SOURCES
源文件列表
FORMS / INTERFACES
ui文件列表
LEXSOURCES
lex源文件列表
YACCSOURCES
yacc源文件列表
TARGET
可执行应用程序名称
DESTDIR
放置可执行目标的目录
DEFINES
应用程序所需的额外的预处理程序定义的列表。
INCLUDEPATH
应用程序所需的额外的包含路径的列表(include文件路径列表)。
DEPENDPATH
应用程序所依赖的搜索路径(描述了建立应用程序所依赖的其他文件所在的路 径)。
VPATH
寻找补充文件的搜索路径。
DEF_FILE
只有Windows需要:应用程序所要连接的.def文件。
C_FILE
只有Windows需要:应用程序的资源文件。
RES_FILE
只有Windows需要:应用程序所要连接的资源文件。
CONFIG变量
配置变量指定了编译器所要使用的选项和所需要被连接的库。配置变量中可以添加任何东西,但只有下面这些选项可以被qmake识别。
下面这些选项控制着使用哪些编译器标志:
release - 应用程序将以release模式连编。如果“debug”被指定,它将被忽略。
debug - 应用程序将以debug模式连编。
warn_on - 编译器会输出尽可能多的警告信息。如果“warn_off”被指定,它将被忽略。
warn_off - 编译器会输出尽可能少的警告信息。
qt - 应用程序是一个Qt应用程序,并且Qt库将会被连接。thread - 应用程序是一个多线程应用程序。
x11 - 应用程序是一个X11应用程序或库。
windows - 只用于“app”模板:应用程序是一个Windows下的窗口应用程序。
console - 只用于“app”模板:应用程序是一个Windows下的控制台应用程序。
dll - 只用于“lib”模板:库是一个共享库(dll)。
staticlib - 只用于“lib”模板:库是一个静态库。
plugin - 只用于“lib”模板:库是一个插件,这将会使dll选项生效。
因为还用不到高级的,那这些就够用了
资源文件
<RCC>
<qresource prefix="/image">
<file>wz.jpg</file>
<file>wz2.jpg</file>
</qresource>
<qresource prefix="/pictrue">
<file>wz.jpg</file>
<file>resourcefile.qrc</file>
<file>wz2.jpg</file>
</qresource>
</RCC>
/*
*Add New File -> Qt Resource File
*列出的资源文件必须位于 .qrc 文件所在目录或其子目录。
*/
//use ways
QMovie *movie =new QMovie(":/image/wz.jpg");
元对象系统
元对象系统提供了信号与槽机制
1.QObject类,为objects提供了一个可以利用元对象系统的基类。
2.Q_OBJECT宏: 在类的私有部分声明这个宏可以启用元对象特性,例如:动态属性、信号与槽。
3.Meta-Object编译器(moc): 为每个QObject子类生成必要的代码来实现元对象特性。
moc工具会读取C++源文件,如果发现有包含Q_OBJECT宏的类声明,就生成另外一个包含这些类的元对象代码的C++源文件。生成的源文件要么在类源文件里用#include包含,或者(更常见)与类的实现代码直接进行编译连接。
QObject::metaObject()返回类关联的meta-object对象。
QMetaObject::className()在运行时以字符串的形式返回类名,无需C++编译器提供运行时类别信息(RTTI)的支持。
QObject::inherits()返回一个对象是否是QObject继承树上一个类的实例。
QObject::tr()和QObject::trUtf8()提供国际化支持,将字符串翻译成指定的语言。
QObject::setProperty()和QObject::property()通过名称动态设置和获取属性。
QMetaObject::newInstance()构造类的一个新实例。
qobject_cast()动态转换QObject类的类型。qobject_cast()函数和标准C++的dynamic_cast()功能类似
QObject *obj=new mywidget;
QWidget *wid=qobject_cast<QWidget *>(obj);
wid->setObjectName("widget");
mywidget *myw=qobject_cast<mywidget *>(wid);
属性
1.要声明一个属性,在继承QObject的类中使用Q_PROPERTY()宏
2.一个属性的行为就像一个类的数据成员,但它有通过元对象系统访问的附加功能。
声明属性需求
如果MEMBER关键字没有被指定,则一个READ访问函数是必须的。它被用来读取属性值。理想的情况下,一个const函数用于此目的,并且它必须返回的是属性类型或const引用。比如:QWidget::focus是一个只读属性,通过READ函数QWidget::hasFocus()访问。
一个WRITE访问函数是可选的,用于设置属性的值。它必须返回void并且只能接受一个参数,属性的类型是类型指针或引用,例如:QWidget::enabled具有WRITE函数QWidget::setEnabled()。只读属性不需要WRITE函数,例如:QWidget::focus没有WRITE函数。
如果READ访问函数没有被指定,则MEMBER变量关联是必须的。这使得给定的成员变量可读和可写,而不需要创建READ和WRITE访问函数。如果需要控制变量访问,仍然可以使用READ和WRITE函数而不仅仅是MEMBER(但别同时使用)。
一个RESET函数是可选的,用于将属性设置为上下文指定的默认值。例如:QWidget::cursor有READ和WRITE函数QWidget::cursor()和QWidget::setCursor(),同时也有一个RESET函数QWidget::unsetCursor(),因为没有可用的QWidget::setCursor()调用可以确定的将cursor属性重置为上下文默认的值。RESET函数必须返回void类型,并且不带任何参数。
一个NOTIFY信号是可选的。如果定义了NOTIFY,则需要在类中指定一个已存在的信号,该信号在属性值发生改变时发射。与MEMBER变量相关的NOTIFY信号必须有零个或一个参数,而且必须与属性的类型相同。参数保存的是属性的新值。NOTIFY信号应该仅当属性值真正的发生变化时发射,以避免被QML重新评估。例如:当需要一个没有显式setter的MEMBER属性时,Qt会自动发射信号。
一个REVISION数字是可选的。如果包含了该关键字,它定义了属性并且通知信号被特定版本的API使用(通常是QML);如果没有包含,它默认为0。
DESIGNABLE属性指定了该属性在GUI设计器(例如:Qt Designer)里的编辑器中是否可见。大多数的属性是DESIGNABLE (默认为true)。除了true或false,你还可以指定boolean成员函数。
SCRIPTABLE属性表明这个属性是否可以被一个脚本引擎操作(默认是true)。除了true或false,你还可以指定boolean成员函数。
STORED属性表明了该属性是否是独立存在的还是依赖于其它属性。它也表明在保存对象状态时,是否必须保存此属性的值。大多数属性是STORED(默认为true)。但是例如:QWidget::minmunWidth()的STROED为false,因为它的值从QWidget::minimumSize()(类型为QSize)中的width部分取得。
USER属性指定了属性是否被设计为用户可见和可编辑的。通常情况下,每一个类只有一个USER属性(默认为false)。例如: QAbstractButton::checked是(checkable)buttons的用户可修改属性。注意:QItemDelegate获取和设置widget的USER属性。
CONSTANT属性的出现表明属性是一个常量值。对于给定的object实例,常量属性的READ函数在每次被调用时必须返回相同的值。对于不同的object实例该常量值可能会不同。一个常量属性不能具有WRITE函数或NOYIFY信号。
FINAL属性的出现表明属性不能被派生类所重写。有些情况下,这可以用于效率优化,但不能被moc强制执行。必须注意不能覆盖一个FINAL属性。
属性类型可以是QVariant支持的任何类型,或者是用户定义的类型。在这个例子中,类QDate被看作是一个用户定义的类型。
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged)
Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)
...
signals:
void colorChanged();
void spacingChanged();
void textChanged(const QString &newText);
private:
QColor m_color;
qreal m_spacing;
QString m_text;
一个属性可以使用常规函数QObject::property()和QObject::setProperty()进行读写,除了属性的名字,不用知道属性所在类的任何细节。
QPushButton *button = new QPushButton;
QObject *object = button;
button->setDown(true);
object->setProperty("down", true);
事件
在Qt中,事件就是对象,派生自QEvent抽象类
事件的运行过程
当一个事件发生时Qt会构造一个事件的对象,它识别事件类型,将事件发送给特定的对象,而后特定的对象将会返回特定的bool
事件机制
bool QCoreApplication::notify(QObject * receiver, QEvent * event) [virtual]
发送事件给接收者,接收者处理并返回状态.
事件处理陈程序
相当于一个虚函数,你也可以自己重写虚函数
事件过滤器
所谓事件过滤就是提前截获发往某个对象的所有消息