随笔分类 - C++
与C++相关的内容
摘要:项目经过长期多人的维护,所谓人多手杂,出现不少过多过长的switch-case分支,或者多重switch-case嵌套。每每添加功能,我都会紧皱眉头,然后带着罪恶感向已经成百上千行的函数里再添上一个case分支,然后纠结地收工了事。于是乎,在我的内心深处,switch-case俨然成了代码坏味道的代名词,写代码时总小心翼翼地避开它们,可往往又事与愿违。事实上,switch-case语句并不是代码坏味道的根源,坏味道来自糟糕的结构设计,过多的switch-case分支,多重switch-case嵌套,这些都将导致代码可读性下降,维护困难易出错。对于分支有多又长的switch-case分支,可是使
阅读全文
摘要:我想这是VC编译器的一个Bug,头文件的包含顺序不该导致运行时产生异常。在VS2008和VC6中都存在同样的问题,但是在C-Free(使用gcc编译器)则一切正常。下面是在VC中产生异常的示例代码,请注意下头文件的包含顺序。定义两个类ClassA和ClassB,在ClassB中定义了一个ClassA的成员函数指针,在ClassB.h中前置声明了ClassA。//// ClassA.h//class ClassA{public: void Func(void) {} void TestA(void);};//// ClassB.h//// 前置声明 ClassAclass ClassA;type
阅读全文
摘要:在C++编程中,成员函数指针并不常用,并且由于它实现比较复杂,很容易导致编程错误。基本用法:classB{public:intf(inta,intb){return(a+b)*m_c;}intm_c;};intmain(){typedefint(B::*MEM_FUNC)(int,int);//定义成员函数指针类型MEM_FUNCMEM_FUNCpmf;//定义成员函数指针pmfpmf=NULL;//指针可以设置为NULLpmf=&B::f;//指针可以指向一个成员函数Bb1,b2;b1.m_c=10;b2.m_c=20;inti1=(b1.*pmf)(30,40);//调用b1.f(
阅读全文
摘要:严防程序模块间通过结构体间接传递STL实例对象经常的,我们通过结构体向函数传递参数。原则上,不应在结构体中包含非POD成员。[引用]===========================================================================POD, plain old data 的缩写,一个普通的古老的数据结构(POD)是一种数据结构。它仅作为被动的收藏的字段值,不使用封包或者otherobject-oriented特征。(A plain old data structure(POD) is a data structurethat is repres
阅读全文
摘要:今天编译了一段程序,运行的时候崩溃了,下断点查看了下崩溃的地方,发现问题出在使用传指针方式向线程传递局部变量。问题代码大致如下:void CStrLenCheckDlg::OnOK(){ THREADINFO info; // 局部变量 info.pDlg = this; info.strFileName = m_strFileName; // 以传指针方式传递局部变量 info 给线程函数 AfxBeginThread(ThreadFunc, &info);}UINT ThreadFunc(LPVOID lpParam){ THREADINFO* p...
阅读全文
摘要:谈到优化,很多人都会直接想到汇编。难道优化只能在汇编层次吗?当然不是,C++层次一样可以作代码优化,其中有些常常是意想不到的。在C++层次进行优化,比在汇编层次优化具有更好的移植性,应该是优化中的首选做法。1 确定浮点型变量和表达式是 float 型为了让编译器产生更好的代码(比如说产生3DNow! 或SSE指令的代码),必须确定浮点型变量和表达式是 float 型的。要特别注意的是,以 "F" 或 "f" 为后缀(比如:3.14f)的浮点常量才是 float 型,否则默认是 double 型。为了避免 float 型参数自动转化为 double,请在函
阅读全文
摘要:使用Incredibuild调动近百台机子,一个完整的build也需要四个小时,恐怖!!!虽然平时开发一般不需要在本地做完整的build,但编译几个相关的工程就够你等上好一段时间的了(老外管这个叫monkey around,相当形象)。想想若干年在一台单核2.8GHZ上工作时的场景 - 面前放本书,一点build按钮,就低头读一会书~~~往事不堪回首。 可以想象,如果不加以重视,编译速度极有可能会成为开发过程中的一个瓶颈。那么,为什么C++它就编译的这么慢呢? 我想最重要的一个原因应该是C++基本的"头文件-源文件"的编译模型: 每个源文件作为一个编译单元,可能会包含上百甚
阅读全文
摘要:问题:从某DLL中导出一个接口函数GetDirFileIdSet用于获取目录下所有文件的ID集合。函数声明如下,该函数传入一个std::set<UINT>类对象:void GetDirFileIdSet(std::set<UINT>& rFileIdSet);当在VS2008中编译的“数据文件编辑器”加载了在VC6中编译的DLL,并调用到GetDirFileIdSet时发生了崩溃。原因:在不同的DLL或EXE中通过指针或引用操作另一个DLL或EXE中的STL类对象时,会遇到严重的程序错误,包括数据错乱或丢失。标准C++库的多数类直接或间接的使用了静态数据成员。由
阅读全文
摘要:公司以前的项目中有的是用fscanf来读取INI文件,这会产生不少问题,键名部分重合便是一个不常出现,但可能出现的问题。这里指的键名部分重合是指在同一节(Section)中,键名间出现类似如下情况:NameAltitude=100Sort=10NameOffsetY=20以上3个字段均是可选项,其中NameAltitude和NameOffsetY的第一个单词出现了重合。NameOffsetY是后来功能需要再添加上去。使用fscanf读取INI文件数据相关代码如下:bool bSucRead = true;// ...// ...// ...// 读取必选键值-BeginbSucRead &am
阅读全文
摘要:在DLL封装的时候,一般都会采用接口类(Interface Class),即纯虚类,达到接口与实现分离的目的。但采用接口类,只能通过返回指针或引用来间接使用被封装的类。相对于这一点,采用句柄类(Handle Class)是个不错的替代方案。句柄类除了名称外,在使用方式上基本同被封装的类无差别。句柄类易用性是建立在耗费一定运行效率的基础之上的(当然,接口类也会消耗一定的运行效率),因此它一般用在运行效率要求不是很高的场合。另外,由于句柄类的编码量比接口类多,所以一般用来封装改动比较小的类。在适当的场景下,使用句柄类是种不错的选择,并且它也能用来封装继承体系,下面是使用句柄类封装继承体系的例子。有
阅读全文
摘要:编辑器加载中... C++提供了内联函数,目的是为了提高函数的执行效率。内联函数在函数声明前面加上关键字inline 就可以了 如:inline int FunctionOne(int x); 在VC++中可使用另一关键字_forceinline 代替inline 关键字.这个关键字将命令编译器跳过一般的ROI 分析(Return On Investment --一种编程缩略语),将所对应的代码强行内联.在有写时候,编译器会拒绝将一个函数内联,使用这个关键字,用户只得到一个编译警告,就可强行内联. 在使用内联函数时,是由编译器决定它们是按普通函数处理还是将调用函数部分用实际的函数体代码替换。不
阅读全文
摘要:1 基本解释 extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。 另外,extern也可用来进行链接指定。2 问题:extern 变量 在一个源文件里定义了一个数组:char a[6]; 在另外一个文件里用下列语句进行了声明:extern char *a; 请问,这样可以吗? 答案与分析: 1)、不可以,程序运行时会告诉你非法访问。原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,因此与实际的定义不同,从而造成运行时非法访问。应该将声明改为extern c
阅读全文
摘要:要编译成DLL,就要声明和实现分开。首先文件组织是这样的(为了简化,没有加上编译成DLL的语句)在 T.h 中(声明模板函数)template<typename T>T Max(T& t1,T& t2);在 T.cpp 中(模板函数的实现)#include"T.h"template<typename T>T Max(T& t1,T& t2){ return t1>t2?t1:t2;}编译 T.cpp 很好,通过编译在 Main.cpp 中(用于测试的)#include<iostream>using n
阅读全文
摘要:一、接口的定义 有时候,我们得提供一些接口给别人使用。接口的作用,就是提供一个与其他系统交互的方法。其他系统无需了解你内部细节,并且也无法了解内部细节,只能通过你提供给外部的接口来与你进行通信。根据c++的特点,我们可以采用纯虚函数的方式来实现。这样做的好处是能够实现封装和多态。现举一实例,供大家参考。(不想做过多说明,大家一看就应该能够明白)Class IPerson{public: IPerson() {}; virtual ~IPerson()=0 {}; //注意,最好定义此虚析构函数,够避免子类不能正常调用析构函数;如果定义为纯虚析构函数,则必须带定义体,因为子类隐含调用该析构函数。
阅读全文
摘要:当读者有一定c/c++基础,推荐的阅读顺序:level 1从《essential c++》开始,短小精悍,可以对c++能进一步了解其特性以《c++ primer》作字典和课外读物,因为太厚不可能一口气看完level 2然后从《effective c++》开始转职,这是圣经,请遵守10诫,要经常看,没事就拿来翻翻接着是《exceptional c++》,个人认为Herb Sutter主席大人的语言表达能力不及Scott Meyers总是在教育第一线的好顺下来就是《more effective c++》和《more exceptional c++》,请熟读并牢记各条款当你读到这里,应该会有一股升级
阅读全文
摘要:下面是我觉得比较能够体现面试官意图的代码://// 模拟 C 标准库函数 strcpy 的实现。// 百度百科词条“strcat”有详细解说.//#include <cstdlib>#include <cassert>#include <iostream>#include <exception>// C++ 中推荐的常量定义方式.const unsigned _MAX_STRING = 100;char* strcpy(char* szDest, const char* szSrc){ // 特殊情况的判断,我觉的使用断言比抛出异常好. asse
阅读全文
摘要:下面的阐述的内容只是对前辈经验的整理。由于早期计算机的内存容量很小,为了尽量节省空间,交换两变量值时不使用中间变量。但这可能暗藏着缺陷。有一个巧妙的函数 swap 是这样编写的:inline void swap(int &a, int &b){ a = a + b; //缺陷1: 可能产生上溢. b = a - b; a = a - b;}引发缺陷 1 的原因是,当 a 和 b 的值比较大,相加之和的实际值大于 int 类型所能表示的数值范围,此时产生上溢。当传入 swap 函数的实参来自同一变量时,将会引发另一个缺陷:int a = 2;// 缺陷 2: 传入同一变量, 变量
阅读全文
摘要:搞笑版优点:多种功能,加快任务实现。缺点:多重性格,易得精神分裂。严肃版优点:对象可以调用多个基类中的接口。缺点:易产生二义性和钻石型继承问题。
阅读全文
摘要:重载(overload)是指在相同的作用域内,不同的函数使用相同的函数名,但函数的参数表不同(参数个数不同,或参数类型不同,或二者都不同)。调用的时候根据函数的参数表来区别不同的函数。覆盖(override)是指子类重新定义父类的虚函数。重新定义的函数与被覆盖的虚函数的函数名和参数表都一样,只是函数的实现不同。
阅读全文
摘要:一个由C/C++编译的程序占用的内存分为以下几个区域:1、栈区(stack)由系统自动分配和释放,用于存放函数的参数值,局部变量值等。其在内存中是一块连续的存储区域,由低地址向高地址延伸。2、堆区(heap)由程序员分配和释放,若程序员不释放,则程序结束时可能由操作系统回收。其存储空间在内存中是不连续,分配方式类似于链表。 3、静态区(static)又称全局区,程序结束后由系统释放,用于存放全局变量和静态变量。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量则存储在相邻的另一块区域。 4、文字常量区程序结束后由系统释放,用于存储常量,字符串常量就是放在这里的。5、程
阅读全文