随笔分类 - C++
摘要:一个类的实例化对象所占空间的大小? 注意不要说类的大小,是类的对象的大小。首先,类的大小是什么?确切的说,类只是一个类型定义,它是没有大小可言的。 用sizeof运算符对一个类型名操作,得到的是具有该类型实体(对象)的大小。 如果 Class A; A obj; 那么sizeof(A)==sizeof(obj)。一个对象的大小大于等于所有非静态成员大小的总和。为什么是大于等于而不是正好相等呢?超出的部分主要有以下两方面:1)C++对象模型本身对于具有虚函数的类型来说,需要有一个方法为它的实体提供类型信息(RTTI)和虚函数入口,常见的方法是建立一个虚函数入口表,这个表可为相同类型的对象共享,因
阅读全文
摘要:1、只有在定义之后,类才可以用作多重继承的基类。按照基类构造函数在派生列表中的出现次序调用。 2、多重继承中,派生类的指针或引用可以转换为任意基类的指针或引用。 3、当一个类继承于多个基类的时候,那些基类之间没有隐含的关系,不允许使用一个基类的指针访问其它基类的成员。 4、在虚继承下,对给定虚基类,无论该类在派生层次中作为虚基类出现多少次,只继承一个共享的基类子对象。 5、特定派生类实例的优先级...
阅读全文
摘要:1、命名空间能够划分全局命名空间。一个命名空间是一个作用域。2、命名空间可以在全局作用域或其它作用域内部定义,但不能在函数或类内部定义。可以在命名空间中放入可以出现在全局作用域的任意声明。3、命名空间作用域不能以分号结束。4、命名空间是累积的。一个命名空间的分离部分可以分散在多个文件中。示例namespace namespace_name{} 既可以定义新的命名空间,也可以添加到现存命名空间中。5、命名空间定义可以不连续意味着,可以用分离的接口文件和实现文件构成命名空间。因此,可以用与管理自己的类和函数定义相同的方法来组织命名空间。示例namespace cplusplus_primer {
阅读全文
摘要:1、auto_ptr为标准库提供的“资源分配即初始化”类,是接受一个类型形参的模板,它为动态分配的对象提供异常安全特性。在memory头文件中定义。2、auto_ptr操作auto_ptr<T> ap;创建名为 ap 的未绑定的 auto_ptr 对象auto_ptr<T>ap(p);创建名为 ap 的 auto_ptr 对象,ap 拥有指针 p 指向的对象。该构造函数为 explicitauto_ptr<T> ap1(ap2); 创建名为 ap1 的 auto_ptr 对象,ap1 保存原来存储在ap2 中的指针。将所有权转给 ap1,ap2 成为未绑定的
阅读全文
摘要:1、类成员的指针不同于指向普通数据或函数的指针,普通指针只根据对象或函数的类型而变化,而成员的指针必须反映成员所属的类。2、异常是通过抛出对象而引发的。该对象的类型决定应该激活哪个处理代码。被选中的处理代码是调用链中与该对象类型匹配且离抛出异常位置最近的那个。异常以类似于将实参传递给函数的方式抛出和捕获。异常可以是可传给非引用形参的任意类型的对象,这意味着必须能够复制该类型的对象。传递数组或函数类型实参的时候,该实参自动转换为一个指针。被抛出的对象将发生同样的自动转换,因此,不存在数组或函数类型的异常。相反,如果抛出一个数组,被抛出的对象转换为指向数组首元素的指针,类似地,如果抛出一个函数,函
阅读全文
摘要:1、用const char*实参调用如下模板,则比较的是指针值,而不是指向的字符串。此时需要模板特化。示例template <typename T>int compare(const T &v1, const T &v2){ if (v1 < v2) return -1; if (v2 < v1) return 1; return 0;}2、函数模板的特化:一个或多个模板形参的实际类型或实际值是指定的。• 关键字 template 后面接一对空的尖括号(<>);• 再接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参;• 函数形参表;•
阅读全文
摘要:1、当函数的返回值必须与形参表中所用的所有类型都不同时,有必要覆盖模板实参推断机制,显式指定为模板形参所用的类型或值。示例sum(static_cast<int>(s), i); 2、指定返回类型的一种方式是引入第三个模板实参:示例template <class T1, class T2, class T3>T1 sum(T2, T3);// poor design: Users must explicitly specify all three template parameterstemplate <class T1, class T2, class T3&g
阅读全文
摘要:1、所谓泛型编程就是以独立于任何特定类型的方式编写代码。使用泛型程序时,我们需要提供具体程序实例所操作的类型或值。 在泛型编程中,我们所编写的类和函数能够多态地用于跨越编译时不相关的类型。2、模板是泛型编程的基础。3、面向对象编程的多态性称为运行是多态性,应用于存在继承关系的类,我们能够编写这样的代码,忽略于基类与派生类之间的类型差异。泛型编程所依赖的多态称为编译时多态性或参数式多态性。4、模板定义以关键字 template 开始,后接模板形参表,模板形参表是用尖括号括住的一个或多个模板形参的列表,形参之间以逗号分隔。模板形参表不能为空。示例代码template <typename T&
阅读全文
摘要:1、在继承情况下,派生类的作用域嵌套在基类作用域中。正是这种类作用域的层次嵌套使我们能够直接访问基类的成员。2、与基类成员同名的派生类成员将屏蔽对基类成员的访问。可以使用作用域操作符访问被屏蔽的基类成员。3、在基类和派生类中使用同一名字的成员函数,其行为与数据成员一样:在派生类作用域中派生类成员将屏蔽基类成员。即使函数原型不同,基类成员也会被屏蔽。4、通过派生类对象调用基类对象时,实参必须与派生类中定义的版本相匹配,只有在派生类根本没有定义该函数时,才考虑基类函数。如果派生类想通过自身类型使用所有的重载版本,则派生类必须要么重定义所有的版本,要么一个也不重定义。可以通过using为基类成员函数
阅读全文
摘要:1、每个派生类对象包含一个基类部分。因此派生类对象也是基类对象。可以将派生类对象的引用转换为基类子对象的引用,同理指针。2、没有从基类引用(或基类指针)到派生类引用(或派生类指针)的(自动)转换。3、编译器不会自动将派生类型对象转换为基类类型对象。4、用派生类对象对基类对象进行初始化(或赋值)时,将发生切割。示例Item_base item; // object of base typeBulk_item bulk; // object of derived type// ok: uses Item_base::Item_base(const Item_base&) construct
阅读全文
摘要:1、继承,动态绑定,数据抽象一起成为面向对象编程的基础。2、模板使我们能够编写独立于具体类型的泛型类和泛型函数。在C++中,用类进行数据抽象,用类派生从一个类继承另一个类:派生类继承基类的成员。动态绑定使编译器能够在运行时决定是使用基类中定义的函数还是类中定义的函数。3、C++中,多态性仅用于通过继承而相关联的类型的引用或指针。4、定义为virtual的函数是基类期待派生类重新定义的。保留字virtual只在类内部的成员函数声明中出现。5、一旦函数在基类中声明为虚函数,它就一直为虚函数。6、派生类对象由多个部分组成:派生类本身定义的(非static)成员加上由基类(非static)成员组成的子
阅读全文
摘要:1、转换分为到类类型与从类类型的转换两种。到类类型的转换:通过转换构造函数;从类类型的转换:转换操作符。2、常用16个操作符:5个算术操作符(+、-、*、/、%)及其对应的复合赋值操作符,4 个关系操作符(<、<=、>、>=),以及相等操作符(==、!=)。示例class SmallInt{public: SmallInt(int i = 0):val(i) { //... } operator int() const {return val;} //转换操作符函数,由SmallInt类类型转换成int型。private: std::size_t val;};Small
阅读全文
摘要:1、自增操作符和自减操作符为了与内置类型一致,前缀操作符应返回被增量或减量对象的引用;后辍式操作符应返回旧值(不是引用)。后辍式操作符函数接受一个额外的(即无用的)int型形参。示例#include "iostream"#include "stdio.h"using namespace std;class CheckedPtr{public: CheckedPtr(int *b, int *e):beg(b), end(e), curr(e){}public: CheckedPtr& operator++(); //前辍 CheckedPtr&a
阅读全文
摘要:1、除了函数调用符之外,重载操作符的形参数目(包括成员函数的隐式this指针)与操作符的操作数目相同。函数调用操作符可以接受任意数目的操作数。表1 可重载的操作符名+-*/%^&|~!,=<><=>=++--<<>>==!=&&||+=-=/=%=^=&=|=*=<<=>>=[]()->->*newnew[]deletedelete[]表2 不能重载的操作符::.*.?:不能通过连接其他合法符号来创建任何新的操作符。2、重载操作符必须具有一个类类型/枚举类型操作数。不能改变内置操
阅读全文
摘要:1、一般采取三种方法1)指针成员采取常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。2)类可以实现所谓的“智能指针”行为。指针所指向的对象是共享的,但类能够防止悬垂指针。3)类采取值型行为。指针所指向的对象是唯一的,由每个类对象独立管理。2、类中定义指针时,需要考虑的有:类的复制,类的赋值,类的析构,共享对象,及悬垂指针。 3、定义智能指针一个行为类似指针但也提供其他功能的类。智能指针的一个通用形式是接受指向动态分配对象的指针并负责删除该对象。用户分配对象,但由智能指针类删除它。智能指针类需要实现复制控制成员来管理指向共享对象的指针。引用计数是实现智能指针的常用方法。注意:是由
阅读全文
摘要:1、显式构造函数复制构造函数是一种特殊构造函数,具有单个形参,该形参(常用 const 修饰)是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数。当将该类型的对象传递给函数或函数返回该类型的对象时,将隐式使用复制构造函数。编译器自动执行类中非static数据成员的析构函数。2、赋值操作符可以通过指定不同类型的右操作数而重载。3、有一种特别常见的情况需要自己定义的复制控制成员的:类具有指针成员。4、C++支持两种初始化形式:直接初始化和复制初始化。复制初始化使用=,而直接初始化将初始化放在圆括号中。当用于类类型对象时,初始化的复制形式和直接形式有所不
阅读全文
摘要:1、构造函数初始化式只在构造函数的定义中而不是声明中指定。2、从概念上讲,可以认为构造函数分两个阶段执行:(1)初始化阶段;(2)普通的计算阶段。计算阶段由构造函数函数体中的所有语句组成。不管成员是否在构造函数初始化列表中显式初始化,类类型的数据成员总是在初始化阶段初始化。初始化发生在计算阶段开始之前。3、使用构造函数初始化列表的版本初始化数据成员,没有定义初始化列表的构造函数版本在构造函数函数体中对数据成员赋值。4、没有默认构造函数的类类型的成员,以及 const 或引用类型的成员,不管是哪种类型,都必须在构造函数初始化列表中进行初始化。5、内置类型的成员不进行隐式初始化,对非类类型的数据成
阅读全文
摘要:1、static成员函数没有this形参,它可以直接访问所属类的static成员,但不能直接使用非static成员。2、可以通过作用域操作符,对象,引用,指针来调用static成员。3、在类外给static成员数据赋值,或定义成员函数时不必要再指定static。4、因为 static 成员不是任何对象的组成部分,所以 static 成员函数不能被声明为 const。毕竟,将成员函数声明为 const 就是承诺不会修改该函数所属的对象;也不能声明为虚函数。保证对象正好定义一次的最好办法,就是将 static 数据成员的定义放在包含类非内联成员函数定义的文件中。5、整型const static数据
阅读全文
摘要:1、成员可以是数据,函数或类型别名(typedef定义的)。2、const必须同时出现在声明和定义中。3、重载的成员函数和普通函数应用相同的规则:两个重载成员的形参数量和类型不能完全相同。也可以根据const来定义。T& display(std::ostream &os){...}const T& display(std::ostream &os) const{...}4、inline在声明和定义处指定都是合法的。5、可以声明一个类而不定义它,这个声明有时称为前向声明(forward declaration),声明的类是一个不完全类型(incompete typ
阅读全文
摘要:1、三种迭代器1)插入迭代器(insert iterator):迭代器适配器,与容器绑定在一起,实现在容器中插入元素的功能。形参为一个迭代器和一个指向容器的引用。• back_inserter,创建使用 push_back 实现插入的迭代器,形参为指向容器的引用的迭代器适配器。• front_inserter,使用 push_front 实现插入。• inserter,使用 insert 实现插入操作。除了所关联的容器外,inserter还带有第二实参:指向插入起始位置的迭代器。Inserter在它的迭代器实参所指的位置前面插入新元素。replace_copy (ivec.begin(), i
阅读全文