个人学习总结整理:
1、头文件包含两点原则
第一个原则
如果可以不包含头文件,那就不要包含了,这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,
那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。
第二个原则
尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用类B的前置声明即可。如果在A的实现中(.cpp)我们需要访问B的具体成员,
因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H 文件)(代码中实际是这样做的)。同理,命名空间的声明也应该尽量放在CPP文件中
2、单例模式
说到单例模式,大家的第一反应应该是——什么是单例模式。单例模式的定义,官方的定义总结起来就两句话,!!确保一个类只有一个实例(也就是类的对象),
并且提供一个全局的访问点(外部通过这个访问点来访问该类的唯一实例)。单例模式的实现其实只有两行代码,定义里面的这两句话分别对应一句代码。
我们用代码来说话。我在这里新建一个控制台应用程序来给大家介绍单例模式。看到这里大家应该能明白,单例模式的实现代码了吧。
namespace _01单例模式
{
class Program
{
static void Main(string[] args)
{
//我们在外部通过全局访问点去访问该类的唯一实例
Singleton s = Singleton.only;
}
}
public class Singleton//单例类
{
//2.提供一个全局访问点(其实就是一个全局静态字段),外部可以通过该字段访问该类的唯一实例
//因为静态字段是属于类的,所以这样可以保证只有一个实例。
public static Singleton only = new Singleton();
//1 将构造函数声明成私有的,这样可以确保在类的外部无法实例化该类(即在类的外部获取不到类的实例)
private Singleton()
{
}
}
}
第一步:[将类的构造函数生命为私有的构造函数],这样我们在外部就无法通过Singleton s = new Singleton()来实例化该,因为Private生命的成员只有在该类的内部可以访问。
这样可以保证类的实例只有一个(那就是在类的内部给它实例化)。
第二步:[在类的里面声明一个公开的全局的静态字段(其实也就是提供一个全局的访问点),外部对象通过这个访问点可以拿到该类的唯一实例]。切记,该字段必须声明成static静态段,
如果声明成非静态字段,那在类的外部就访问不到了。因为非静态成员只能通过类的实例去访问,而我们在类的外部是无法对该类进行实例化的。
注: 接下来的就是第二个问题,单例模式的作用是什么呢?其实定义单例模式的定义已经给了我们答案,作用就是————使得类的一个对象成为系统中的唯一实例。说了好像和没说一样吧,
举个例子你就知道他有什么好处了。一个操作系统中可以存在多个打印任务,但我们只有一个打印机,同一时间只能有一个正在工作的任务,这个时候内存中打印机的这个类就必须是单例的,
否则的话就可以同时执行多个打印任务,这显然会造成错误。
template<typename T>
struct Singleton
{
static T& getInstance()
{
static T instance;
return instance;
}
DISALLOW_COPY_AND_ASSIGN(Singleton)
protected:
Singleton() {}
};
#define DEF_SINGLETON(object) struct object : Singleton<object>
3、命名规范:
3.1 采用驼峰命名 ,如: getUrl、orgID
注意:
缩写为两个字母时,全部大写
常量名全大写,如:EMP_ID
魔法数字、字符统一提取,用常量
3.2 方法名、变量名有意义,如:
String params = ht.get(Constatnt.MSB_INTERFACE_PARAMS); // 此处为MSB微服务调用入参
String i = "1033";//
3.3 接口地址,全部小写,如:
/srv/usercenter
4、函数对象
4.1 bool operator() //提供一个本类型到bool的隐式转换,不允许使用参数
4.2 例:
struct ShouldRollBackSts
{
bool operator()(const TransactionInfo& trans) //为类类型的对象重载函数调用操作符
{
TRANS_TO_ROLE_BOOL(StState, state);
return (state)->shouldRelease();
}
};
5、const对象是不可以调用类中的非const成员函数
解析:
class test{
int i;
public:
void print();
test(int i);
};
test obj1(12);
obj1.print(); //ok
如果用test类创建一个const对象,然后去调用print()函数呢?这就会出现问题
const test obj2(122);
obj2.print();
###这时obj2对象的指针就会传递给test *this 指针,而obj2的地址翻译成指针类型应该是这样的,const test* this,即这时会出现类型不匹配的错误!!(不能将const指针转换为非const指针)
6、printf(",0x%02x",req[i]);
%02x : 表示以16进制的格式输出整数类型的数值,输出域宽为2,右对齐,不足的用字符0替代
( 前边的0x直接输出,后面的%02x是输出十六进制的数,保留两位有效数字)
7、 operator 重载
Status F1CtxtRelCmdReportAction::exec(const TransactionInfo& trans)
{
BYTE counter;
TRANS_TO_ROLE(UeCtxtRelCause, cause);
if((cause->getTriggerMs() == ReleaseTrigger_Pps)&&(cause->operator unsigned int() == lucm_if::PpsTransmissionMessage_ErrorCause_rlf) //显示调用operator转换函数
|| (cause->getTriggerMs() == ReleaseTrigger_Spa))
{
counter = UeCtxtRel_RLF;
}
else
{
counter = UeCtxtRel_Other;
}
F1UeCtxtRelStatReporter::report(trans, counter);
return DCM_SUCCESS;
}
UeCtxtRelCause::operator Status() const // typedef unsigned int Status; //转换函数 ***
{
return toolCause.isPresent() ? toolCause->cause : DCM_SUCCESS;
}
8、[*******类的普通数据成员不能在定义体内初始化]
C++中类的数据成员不管是不是私有的,都不能进行初始化。因为类就相当于一个数据的模板,是一种自定义组合的新数据类型,而不是一个变量。当程序声明一个类的时候,
事实上并没有为程序申请存储空间,只有用这个类定义一个类对象的时候,才申请空间。连空间都没有,当然不能像定义变量一样的初始化了。
(例外:当初始化式是一个常量表达式时,整型const static数据成员就可以在类的定义体内进行初始化)
若一定要在类内初始化静态成员,那么就必须满足如下条件才行:
1) 静态成员必须为字面值常量类型的constexpr。
所谓的字面值类型就是通常遇到的:算术类型,引用,指针等。字面值常量类型就是const型的算术类型,引用,指针等。
所谓的constexpr,就是常量表达式,指值不会改变且在编译过程中就能得到计算结果的表达式。比如字面值,或者用常量表达式初始化的const对象也是常量表达式。
为了帮助用户检查自己声明/定义的变量的值是否为一个常量表达式,C++11新规定,允许将变量声明为constexpr类型,以便由编译器来进行验证变量是否为常量表达式。
2)给静态成员提供的初始值,必须为常量表达式。
9、gdb调试
9.1、gdb ftest
9.2、(gdb) b DedicatedMsgTransferHandler.cpp:1061 //打断点
b + 偏移量
b 函数名
info b //查看断点
9.3、(gdb) run --gtest_filter=FtAttach.should_attach_succ_am_with_msg4_opt_on verbose // 跑ft
run (r)
执行源源代码中一行的命令 next(简称n)//执行时如果遇到函数调用,可能想执行到函数内部,这时用step(简称p)
continue(c) / continue + n 忽略指定次数的断点
delete(d) d+编号 //删除断点或监视点
9.4、(gdb) p/x *dirTransMsg //打印
p argv
p *argv
p argv[0] // 首元素指针
p argv[1]
p/格式 变量
格式 x 显示为16进制
d 显示为10进制
u 无符号10进制数
c 显示为字符 ASCII
f 显示为浮点小树
a 地址
9.5******[监视点]!!!
watch <表达式> //表达式发生变化时暂停
awatch <表达式> //表达式被访问、改变时暂停
rwatch <表达式> // 被访问时暂停
9.6*******
set $s= drbContext.qosFlow.size()
9.7 bt 查看调用堆栈 breaktrace
10、//ecplise 打开工程
****/ft/uc/project/setting.xml
**[UCM代码转换成 C++Project ] 右键选择工程 new/other/ (C/C++) / Convert to a C/C++ Project (add C/C++ nature)
11、std::to_string(cpfUeId).c_str() to_string使用
12、error: passing 'const HasPtr' as 'this' argument of 'const string HasPtr::getPs()' discards qualifiers [-fpermissive]|
常见原因:常量引用不能够调用非常量成员函数。
13、C++ override关键字 // 关键字and 保留字
描述:override保留字表示当前函数重写了基类的虚函数。
目的:1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。
用法:在类的成员函数参数列表后面添加该关键字既可。
注意:override只是C++保留字,不是关键字,这意味着只有在正确的使用位置,oerride才启“关键字”的作用,其他地方可以作为标志符(如:int override;是合法的)
final关键字:
final关键字来限制类不能被继承,或者虚函数不能被重写
class A final
{
virtual void hehe() final;
}