C++学习笔记
文章平均质量分 72
friendbkf
Bingo! macrofun is me too.
展开
-
extern "C" 学习笔记
从直观上来讲,extern "C" 显然有两层含义。其一,是 被它修饰的目标是“extern”,即该目标具有外部链接性,可以在其他编译单元(文件)中被引用。其二,被它修饰的目标是“C”类型的,即编译器或链接器要按照C的编译规则来对其进行编译或链接。 作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。即C++ Primer中所说的“名字粉碎”(name mangling)或“名字修饰”(name decoration)。原创 2015-04-03 10:01:16 · 450 阅读 · 0 评论 -
命名空间、using声明和using指示【附送彩蛋】
一般来说,使用using声明总是对的,使用using指示总是会带来风险的。using指示引发的二义性错误只有在使用了冲突的名字的地方才能被发现。这种延后的检测意味着可能在特定库引入很久很久之后,才爆发冲突。using声明不是不会引起冲突,而是,由using声明引起的二义性问题在声明处就会被发现,无须等到使用名字的地方,这显然对检测并修正错误大有益处。但using指示并不是一无是处,例如在命名空间本身的实现文件中,就可以使用using指示。原创 2015-04-21 20:19:47 · 2331 阅读 · 1 评论 -
派生类的复制构造函数与赋值运算符
当你声明自己的拷贝函数时,也就意味着你告诉了编译器你并不喜欢缺省实现中的某些行为,比如浅拷贝。编译器仿佛被冒犯了一样,会以一种奇怪的方式回敬你:当你的代码几乎百分之百出错时,却保持沉默,甚至连一个小小的警告也没有,即使是开了最高级别的编译器警告。比如下面这个例子,输出的结果与期望大相径庭!!!//class.h#ifndef CLASS_HEAD_FILE#define CLASS原创 2015-05-17 10:25:00 · 1170 阅读 · 2 评论 -
【移动语义和精准转发系列二】std::move和std::forward
在我们开始讲解std::move之前,先来介绍一个概念:引用折叠。这个概念仅用于 typedef 和 模板类型参数 中。在模板世界中,T&& 称为Universal Reference,即通用引用。这与普通函数中形参的&&是不同的,希望不要弄混了。对于模板函数template void func(T&& t),对于左值实参,T&& t 推导出的T为string&;对于右值实参,T&& t原创 2015-05-28 20:18:41 · 1846 阅读 · 0 评论 -
【移动语义和精准转发系列一】移动语义
std::move和std::forward是C++0x中新增的标准库函数,分别用于实现移动语义和精准转发(完美转发)。这篇文章中,我们先只对移动语义进行阐述。一、在进行移动语义的阐述前,我们先介绍一下右值对象的概念。C++03 3.10/1 中说,每一个表达式,左值或右值必居其一。认识到一点很重要,即:左右值是表达式的属性,而不是物件的。左值表示一个对象可以在该表原创 2015-05-28 18:17:36 · 939 阅读 · 0 评论 -
用CRTP 避免无意共用基类的静态成员变量
当两个派生类从同一个基类继承时,如果基类中有静态成员变量,那么这两个子类将会共用同一个基类的静态成员变量。有了这个理论,我们来看代码。//myClass.h#include class base {public: static int S_iNum;};class derived1 : public base {};class derived2 : public base原创 2015-06-17 10:03:25 · 785 阅读 · 0 评论 -
模板函数需要注意的两条重载规则
规则一:首先,特化的模板函数是不参与重载解析的。这就意味着一开始的时候,特化的版本就不会被考虑。只会考虑普通的和模板两种。如果没有普通那么就选用模板的。规则二:然后,实例化模板。实例化之后,如果实例化之后的,和特化版本参数一致,那么采用特化版本。下面举例来证明上述规则。先来看一个例子,它的输出会出乎我们的意料。#include #include #include #inclu原创 2015-05-28 17:06:12 · 626 阅读 · 0 评论 -
宏 备忘录
define中的三个特殊符号:#,##,#@#define Conn(x,y) x##y#define ToChar(x) #@x#define ToString(x) #x(1) x##y 表示什么?表示x连接y,举例说:int n = Conn(123,456);/* 结果就是n=123456;*/char* str= Conn("asdf","adf"); /*原创 2015-05-21 22:05:48 · 477 阅读 · 0 评论 -
用C和C++,两种方式实现C语言中的printf函数
理论准备C++中的类C可变形参函数首先,我们来看一下C++中的类C可变形参函数。可变形参函数,表示函数形参的类型和个数都可以变化。C语言中的 printf, scanf 就是最常见的可变形参函数。为了和C语言兼容互通,C++引入了省略符形参。通常,声明一个可变形参函数为如下的形式:void printf(const char* format,...);void printf(cons原创 2015-05-20 21:36:34 · 3266 阅读 · 0 评论 -
指向public成员函数的指针
C++中,所谓普通成员函数,无非就是比普通函数在形参列表的最后,多了一个这个类型的this指针,本质上和一般的函数没有什么不同。而类的静态成员函数,则和普通函数完全一样。所以声明函数指针时,对于类的静态成员函数,方法和普通函数指针是一样的。对于普通成员函数,则有一点区别。受this指针的影响,类的非静态成员函数与一般函数指针是不兼容的。而且,不同类的this指针是不一样的,因此,指向不同类原创 2015-05-23 09:56:13 · 716 阅读 · 3 评论 -
std::function介绍
std::function介绍类模版std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标实体进行存储、复制、和调用操作,这些目标实体包括普通函数、Lambda表达式、函数指针、以及其它函数对象等。std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的)。转载 2015-05-23 20:23:16 · 676 阅读 · 0 评论 -
C++的三种继承方式(本文先不涉及虚继承)
private继承截断了继承的访问通道,下一个孙子派生类将无法访问爷爷基类的public和protected成员,同时关闭了派生类对象直接访问基类public成员的通道。protected继承则依旧保持了继承访问通道的畅通,但同时也关闭了派生类对象直接访问基类public成员的通道。 派生列表中的访问说明符,对于 派生类中的成员函数和友元函数能否访问 派生类的基类部分的成员,不会产生任何影响。派生访问说明符,是用于控制派生类用户(包括派生类的派生类在内),对于派生类的基类部分的成员的访问权限。派生原创 2015-04-17 14:54:27 · 993 阅读 · 1 评论 -
typeid()和dynamic_cast<>()
一旦提到typeid()函数,就不得不提RTTI了。RTTI(Run-Time Type Information 运行时类型信息),指程序有能力识别 基类的指针或引用 在运行时实际指向的对象的类型信息。C++中与RTTI相关的操作符有两个:(1)typeid 操作符:返回指针或引用所指对象的实际类型。(2)dynamic_cast 操作符:将基类类型的指针或引用安全地转换为派生类型原创 2015-05-11 15:00:18 · 682 阅读 · 0 评论 -
说说std::endl函数
所谓std::endl,原来就是一个模板函数名,相当于函数指针啊。该函数以引用的方式接收一个输出对象,经过处理后,再以引用的方式返回该对象本身。#include <iostream>int main(void){ endl(std::cout << "Test 4 std::endl"); endl(std::cout << "Here is the 2nd Line!");}请不要对endl前面不加std命名空间限定符感到不解,请查看Koenig looup法则,或者叫ADL法原创 2015-11-27 16:58:08 · 6699 阅读 · 2 评论 -
QProcess:进程通信之无名管道
进程间通信(IPC)方式包括:管道,FIFO,信号。这里只提下无名管道,用于有亲缘关系的进程之间。有名管道可以用在没有亲缘关系的进程之间。QProcess,底层使用的就是无名管道。做了一个小demo,毕设有一块要用到。用于子进程的程序:#include #include using std::cout;using std::endl;int main(void){原创 2015-11-19 19:49:56 · 6123 阅读 · 1 评论 -
查看虚函数表和类内存布局,以及使用MSVC与GCC hack验证
方法其实很简单。1.打开VS自带的命令行工具。2.使用cl命令的/d1 reportAllClassLayout或reportSingleClassLayoutXXX选项。这里的reportAllClassLayout选项会打印大量相关类的信息,一般用处不大。而reportSingleClassLayoutXXX选项的XXX代表要编译的代码中类的名字(这里XXX类),打印X原创 2015-11-16 18:22:17 · 2166 阅读 · 1 评论 -
初始化列表的顺序应该是按照你成员声明顺序初始化
初始化列表的顺序应该是按照你成员声明顺序初始化。原创 2015-11-20 20:46:49 · 1361 阅读 · 0 评论 -
有缺陷的枚举类型 和 C++11中的强类型枚举
首先第一点,我们要弄清一个概念,那就是枚举类型的名字都在其父作用域空间 可见的。举个例子就一目了然了。enum Type { General, Light, Medium, Heavy };enum Category{ General, Pistol, MachineGun, Cannon };由于Category中的General和Type中的General都是全局的名字,因此编译原创 2015-08-17 17:12:35 · 2821 阅读 · 0 评论 -
C++重载 箭头运算符
箭头操作符(->)的内置用法是,使用一个类对象的指针来调用所指对象的成员。左操作数为对象指针,右操作数为该对象的成员。定义重载箭头操作符之后看起来就有点特别,既可用类对象的指针来调用,也可用类对象直接调用。重载箭头操作符,首先重载箭头操作符必须定义为类成员函数。箭头操作符与众不同。它其实是一元操作符,却表现得像二元操作符一样:接受一个对象和一个成员名。对对象解引用以获取成员。不管外原创 2015-05-24 09:06:27 · 5422 阅读 · 4 评论 -
typedef用法总结
右左法则理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:int (*func)(int *p);首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一转载 2015-05-08 14:54:54 · 401 阅读 · 0 评论 -
C++中的关键字 volatile 详解
突然想到一个解释volatile关键字的很好的例子。就当做引子,来讲一讲这个关键字吧。const int iNum = 0;int *iPtr = const_cast(&iNum);*iPtr = 5;cout << "iNum = "<< iNum << endl;cout << "*iPtr = " << *iPtr << endl;cout << "addr iNum: "原创 2015-05-06 22:29:46 · 3375 阅读 · 1 评论 -
链接性 杂谈
即使是使用 __forceinline参数, 编译器也不是在所有的情况下都能把函数成功内联。在以下任何一种情况下,函数内联是会失败的:函数或它的调用者被以 /Ob0 参数进行编译,该参数也就debug模式的默认参数。(也就是说,debug版本不会内联任何函数)函数和它的调用者使用了不同类型的异常处理。(The function and the caller use differen原创 2015-05-10 15:20:14 · 1008 阅读 · 2 评论 -
C++重载(overload)、重写(overwrite,也称隐藏)、覆盖(override)
一、重载(overload)函数名相同,但是它的参数列表中参数的个数、类型或顺序不同。不能靠返回类型来判断。这个最简单,name mangling。 二、重写(overwrite,也称隐藏)重写一定是分别位于派生类与基类中。对于声明在内层作用域的函数,并不会重载声明在外层作用域的函数。因此,定义派生类中的函数也不会重载其基类中的同名成员,而只会隐藏该基类成员。即使派生类成员和基类成员的形参列表不一致,基类成员也仍然会被隐藏掉。 三、覆盖( override)一定也是分别位于派生类与基类中的,原创 2015-04-22 12:18:36 · 2439 阅读 · 0 评论 -
C++中的inline函数
程序员都知道,普通的函数被调用时有压栈弹栈的操作,同时伴随着指令跳转。这都消耗着时间和资源。如果函数本身规模很小,则这种消耗就占用了很大的比例。为解决这种问题,引入了inline函数。注意,C++中的inline函数的链接性是内部的,这意味着函数定义必须放在使用函数的文件中。对于内联函数在头文件中,因此在使用函数的文件中包含头文件可以确保将定义放在正确的地方。对于将函数定义原创 2015-05-10 09:43:10 · 547 阅读 · 0 评论 -
【转载】实实在在说多态
原文地址实实在在说多态(C++篇)1. 什么是多态2. 多态带来的好处3. C++中实现多态的方式4. 细说用函数重载实现的多态5. 细说用模板函数实现的多态6. 小结7. 细说用虚函数实现的多态7.1. 虚函数是怎么回事7.2. 向上转型7.3.转载 2015-05-09 16:48:25 · 439 阅读 · 0 评论 -
const T*& 指针的引用、指针的指针、const
我们用T来表示类型,这里的类型可以是系统内置类型,也可以是用户自定义类型。我们先来熟悉一下这种表示方法。这样的表示在模板中是很常见的。const T* 表示指针指向的是一个T类型的变量,该指针具有底层const属性,也就是说通过该指针,只能读取指向对象的值,但不能修改其指向对象的值。同理,const T&表示常引用,所引用的也是T类型的也是底层const,也就是说通过该引用,只原创 2015-05-08 15:10:34 · 662 阅读 · 0 评论 -
T** 不能隐式转换成 const T** 的原因
我们用T来表示类型,这里的类型可以是系统内置类型,也可以是用户自定义类型。首先要明确一点:将T** 类型的指针赋给 const T**类型的指针是不合法的,即使你非要强制转换来赋值,那样做也是十分危险的。大家都知道,C++允许我们将T*类型的指针赋值给const T*类型的指针,这是因为const T*类型的指针具有底层const属性,它可以保证通过它,你不能修改它指向的内容。但是原创 2015-05-08 18:35:50 · 1476 阅读 · 0 评论 -
收集整理的 C++常用表(方便查询)
C++运算符优先级表 和 ASCII表原创 2015-05-08 14:09:43 · 1416 阅读 · 0 评论 -
C++11中的新关键字:auto与decltype
autoC++11之前,最无用的关键字我们知道,在C++11以前,auto关键字的作用是声明函数内的局部变量为自动的变量。也就是说,它的作用是指出当前的变量为局部变量。是不是很多余?在函数里面声明整型局部变量,直接用 int i 就可以了,几乎没有人写成“规范”的 auto int i。所以auto成为了C++11之前最无用的关键字。但是C++11标准来了,auto以前的作法全原创 2015-05-06 21:59:43 · 1165 阅读 · 2 评论 -
重载前置++运算符和后置++运算符
运算符重载的主要目的是为了让用户自定义类型对象可以像普通数据类型一样能够进行加减乘除,自加自减等操作,非常直观方便。在这里总结一下C++的++(分前置与后置)运算符的重载。自减运算符同理。关键就是如何通知编译器,让它知道哪个是前置版本,哪个是后置版本。如何让编译器知道是前置还是后置呢?其实很简单,只要在重载操作符的形参中加上一个整数型参数,编译器就会自动将这个函数标示为后置,相应的不加则是原创 2015-05-11 15:50:22 · 5272 阅读 · 0 评论 -
不同作用域的重名问题
先看一段代码,如果不看后面的讲解,你就能看懂,那表明你已经明白了不同作用域的同名变量覆盖问题了。这段小程序的输出结果是什么?#include #include typedef int INT4;class Oops{};Oops& operator< (Oops &ref1 , Oops &ref2){ std::cerr << "Amazing!" << std::end原创 2015-05-11 19:50:06 · 1417 阅读 · 0 评论 -
【浅析】把实现放在头文件中的函数模板,为什么没有发生重定义错误
对于普通函数,典型的做法是在头文件中只放入声明,而定义写在别外的.cpp文件中。然后在要使用该函数的源文件中直接include头文件,即该函数的声明 即可。但是对于模板函数,情况就不一样了。在要使用该模板函数的源文件中,既要include模版函数的声明,也要include模版函数的定义。因为只有在编译的时候,根据调用处的类型进行隐式实例化后,由编译器生成的函数才是真正的函数定义。原创 2015-05-01 17:12:58 · 1966 阅读 · 5 评论 -
类的const变员变量和static成员变量的初始化总结
I 类的非static 的const成员变量的初始化只有1种方法:class CostEstimate {public: CostEstimate();private: const double FudgeFactor;};只能在构造函数的初始化列表中进行://class.cppCostEstimate::CostEstimate() : FudgeFactor(1原创 2015-05-15 20:57:37 · 701 阅读 · 0 评论 -
iterator的顶层const与底层const
STL迭代器是以指针为根据塑模出来的,所以迭代器的作用就像是一个T* 指针。声明迭代器为const 就像是声明指针为顶层const 一样(即声明一个T* const 指针),表示这个迭代器不能指向别的东西,但是它所指的东西是可以改动的。也就是说,const iterator 这表示迭代器本身是一个const。如果你希望迭代器所指向的东西不可被改动,即希望STL模拟一个 const T* 指原创 2015-05-15 21:05:45 · 651 阅读 · 0 评论 -
顶层const、底层const、函数重载与const形参
1.顶层const可以表示任意的对象(任何数据类型)是常量。而底层const则与指针和引用等复合类型的基本类型部分有关。2.对于拷贝操作,顶层const没有什么要求,而底层const要求左值必须比右值更严格。函数重载机制会自动假装忽略掉顶层const而保留底层const。3.对于函数形参中的引用,尽量使用常量引用。首先,如果使用普通引用,会带给调用者一种误导,即函数可以修改它的实参的值。此外,使用普通引用而非常量引用,也会极大地限制函数所能接受的实参类型。因为我们不能把const对象、字面值或者需要类型原创 2015-05-01 12:01:11 · 1843 阅读 · 1 评论 -
reverse_iterator的补偿机制
反向迭代器(Reverse Iterator)是一种反向遍历容器的迭代器。比如,vector类中有一个名为rbegin()的成员函数和一个名为rend()的成员函数。rbegin()返回一个指向超尾的反向迭代器,rend()返回指向第一个元素的反向迭代器。正因为它是反向迭代器,所以将自增(和自减)的含义反过来了:对于反向迭代器,++运算将导致它被递减,--运算将导致它被递增。我们来看一下它原创 2015-05-13 11:14:29 · 677 阅读 · 0 评论 -
五种迭代器汇总 From C++ Primer Plus 6th
要解释一下什么是输入和输出。输入迭代器术语“输入”是程序的角度说的,即来自容器的信息被视作为输入,就像来自键盘的信息对程序来说是输入一样。因此,输入迭代器可被程序用来读取容器中的信息。,但不一定能让程序修改容器中的值。因此,需要输入迭代器的算法将不会修改容器中的值。顺便说一句,并不能保证输入迭代器第二次遍历容器时,顺序不变。输入迭代器被递增后,也不能保证其先前的值仍然可以被解除引用。基转载 2015-05-12 22:02:56 · 907 阅读 · 0 评论 -
函数和类的默认参数的位置
普通函数默认参数指的是形参的默认值。默认参数是在函数声明中提供。在函数声明与函数定义这两个地方,默认参数只能出现一次。当既有声明又有定义时,如果函数定义是出现在函数调用点的后面,则定义中不允许默认参数。当既有声明又有定义时,如果函数定义是出现在函数调用点的前面,则可以在定义中使用默认参数。如果函数只有定义,没有函数声明时,则默认参数可以出现在函数定义中。对于上述规则,我们可原创 2015-05-12 10:54:06 · 2621 阅读 · 1 评论 -
【资料整理】“将模板放在头文件中”
在讲到C++中的模板时,书上的一句话让我在网上搜过了一番。学习后整理如下,以备后查。书上原话为:【将模板放在头文件中,并在需要使用模板的文件中包含头文件】。以下整理自网上。“通常情况下,你会在.h文件中声明函数和类,而将它们的定义放置在一个单独的.cpp文件中。但是在使用模板时,这种习惯性做法将变得不再有用,因为当实例化一个模板时,编译器必须看到模板确切的定义,而不仅仅是它的声明。因此转载 2015-05-01 15:29:16 · 1019 阅读 · 0 评论 -
关于ADL的查找顺序
argument-dependent lookup或Koening lookup法则当我们给函数传递一个类类型的对象时,首先会在常规的作用域查找,其次在实参类所属的命名空间查找。查找顺序如下:1. 先在本作用域内查找;2. 在实参的命名空间 和 全局作用域中 同时查找;这一规则也叫做argument-dependent lookup或Koening lookup法则。这原创 2015-06-01 11:07:00 · 1337 阅读 · 0 评论