C++必知必会(1)

条款1数据抽象

抽象数据类型的用途在于将变成语言扩展到一个特定的问题领域。一般对抽象数据类型的定义须要准训下面步骤:

1.     为类型取一个描写叙述性的名字

2.     列出类型所能运行的操作

3.     为类型设计接口

4.     实现类型

条款2多态

多态类型,从基类继承的最重要的多系就是它们的接口,而不是它们的实现。

条款3设计模式

条款4 STL

STL优秀思想体如今:容器与在容器上运行的算法之间无需彼此了解。这样的戏法是通过迭代器实现的。STL容器和算法分别通过类模板和模板函数实现。

条款5引用时别名而非指针

引用必须被初始化,一个引用即使在该引用被初始化之前已经存在的一个对象的别名。

一个指向很量的引用是不能够用字面值或暂时值进行初始化的。

而一个指向常量的引用就能够。当一个指向常量的引用採用一个字面值来初始化时,该引用实际上被设置为指向採用该字面值初始化的一个暂时位置。

引用和指针的差别:

1.不存在空引用

2.全部引用都须要初始化

3.一个引用永远指向用来对它初始化的那个对象

条款6数组形參

事实上C/C++中根本不存在所谓的数组形參,由于数组在传入时,实质之传入指向其首元素的指针。数组被作为性參数会丢失边界。

void average(intary[]); 与 void average(int ary[12]);作用一样。

还有一方面,假设数组边界的精确数值很重要。而且希望函数仅仅接受含有特定数量元素的数组,能够考虑使用一个引用形參:

void average(int(&art)[12]);   //如今函数仅仅能接受大小为12的整形数组

模板有助于代码的泛华:

template<intn>

void average(int(&ary)[n]);    //让编译器帮我们推导n的值

只是,更传统的做法是将数组的大小明白的传入函数:

void average(intary[], int size);

当然我们能够将这两种方法结合起来

template<intn>

inline voidaverage(int (&ary)[n])

{

average(int ary, n);

}

为保证数组边界不丢失,数组的大小必须以形參的方式显示的编码,并以单独的实參传入或者在数组内部以一个结束符值作为指示(比如用于指示“用作字符串的字符数组”的末尾’\0’)。无论数组是怎样声明的,一个数组一般是通过指向其收元素的指针进行操作的。

因为这些原因。常常採用某种容器(vector或string)来替换数组的大多数传统使用方法。

多维数组是数组的数组,因此形參是一个指向数组的指针。

void process(int(*ary)[20]);    //一个指针,指向一个具有20个int元素的数组

注意第二个边界没有退化,否则无法对形參运行指针算术。

对于多维数组形參的有效处理例如以下:

void process(int*a, int n, int m)

{

for(int i=0; i<n; ++i)

for(int j=0; j<m; ++j)

{

a[i*m+j] = 0;              //手工计算索引

}

}

相同,有事模板有助于让事情更干净利落:

templat<intn, int m>

inline voidprocess(int (&ary)[n][m])

{

process(&arr[0][0], n, m);

}

条款7常量指针和指向常量的指针

const T* pct = pt;              //一个指向const T的指针

T* const cpt = pt;              //一个const指针,指向T

能够将一个指向很量的指针转换为一个指向常量的指针。但不能将指向常量的指针转化为指向很量的指针。

条款8指向指针的指针

有两种情况会看到指向指针的指针:

1.     声明指针数组时,因为数组名会退化为指向其首元素的指针。所以指针数组的名字也是一个指向指针的指针。

2.     当一个函数须要改变传递给它的指针的值时。

通常,C++中秀安使用指向指针的引用作为函数的參数,而不是指向指针的指针作为參数。

一个常见的误解是:适用于指针的转化相同适用于指向指针的指针。事实并不是如此。例如以下:

Circle* c = new Circle;

Shape* s = c;              //正确

Circle **cc = new Circle;

Shape** ss = cc;  //错误

由于Circle是一个Shape。因而一个指向Circle的指针也是一个Shape指针。然后,一个指向Circle指针的指针并非一个指向Shape指针的指针。

当设计const相同会发生混淆。我们知道将一个指向很量的指针转化为一个指向常量的指针是合法的。但不能够将一个指向“指向很量的指针”的指针转化为一个“指向常量的指针”的指针。

char*  s1 = 0;

const char* s2 =s1;   //没问题

char* a[MAX];            //也就是char**

const char ** ps= a;  //错误。

条款9新式转型操作符

const_cast操作符同意加入或移除表达式中类型的const或volatile修饰符。

static_cast操作符用于相对而言可跨平台的转型。

最常见的情况是,它用于将一个继承层次结构中的基类的指针或引用。向下转型为一个派生类的指针或引用。

reinterpret_cast从位的角度来对待一个对象,从而同意将一个东西看做还有一个全然不同的东西。

dynam_cast通经常使用于运行从指向基类的指针安全地向下转型为指向派生类的指着。不同static_cast,dynamic_cast仅用于对多态进行向下转型(也就是说,被转型的表达式的类型,必须是一个指向带有虚函数的类类型的指针),而且运行运行期检查工作,来推断转型的正确性。

条款10常量成员函数的含义

在类X的很量函数中,this指针的类型为X*const。

也就是说,它指向很量X的常量指针。因为this指向的对象不是常量,因此它能够被改动。而在类X的常量成员函数中,this的类型为const X* const。也就是说,是指向常量X的常量指针。因为指向的对象是常量。因此它不能被改动。

类的非静态数据成员能够说声明为mutabl,这将同意它们的值能够被该类的常量成员函数改动,从而同意一个逻辑上为常量的成员函数被声明为常量,尽管事实上现须要改动该对象。

一个成员函数的常量版本号和很量版本号能够重载。

常量对象调用常量版本号。

条款11编译器会在类中放东西

假设类声明了一个或多个虚函数,编译器会为该类插入一个指向虚函数表的自指针。

有时使用了虚拟继承,即便类没有虚函数,当中还是有可能被插入一个虚函数表指针。

由于跨平台的内存布局不同的原因,不要使用memcpy这种标准内存块复制函数,而应该使用对象的初始化或赋值操作。

条款12赋值和初始化并不同样

赋值发生于赋值时,除此之外。所遇到其它的复制情形均为初始化,包含声明、函数返回、參数传递以及捕获异常中的初始化。

初始化操纵:先分配内存用于容乃字符串的复制,然后运行复制操作

赋值有一点像析构动作后跟一个构造动作。

条款13复制操作

复制构造函数和赋值函数总是成对的声明。

复制构造函数被声明为X (const X &),而复制赋值操作应被声明为&operat = (const X &)。

条款14函数指针

能够声明一个指向特定类型函数的指针:

void (*fp)(int);     //指向函数的指针

它表示fp是一个指向返回值为void的函数的指针。就像指向数据的指针一样,指向函数的指针也能够是空,否则它就应该指向一个具有适当类型的函数。

extern void h(int);

fp = h;    //正确

fp = &h; //正确

将一个函数的地址初始化或赋值给一个函数的指针时,无需显式地取得函数地址。编译器知道隐式地获取函数的地址。因此在这样的情况下&操作符时可有可无的。

类似地,为了调用函数指针所指向的函数而对指针进行解引用操作也是不必要的。由于编译器能够帮你解引用。例如以下:

(*fp)(12);      //显示解引用

fp(12);          //隐式地解引用,结果同样

和void*指针能够指向不论什么类型的数据不同,不存在能够指向不论什么类型函数的通用指针。还要注意,非静态成员函数的地址不是一个指针,因此不能够将一个函数指针指向一个非静态成员函数。

函数指针的一个传统用途是实现回调。一个回调就是一个可能的动作,这个动作在初始化阶段设置。以便对将来可能发生的事件做出反应时而被调用。

一个函数指针指向内联函数时合法的,然而通过函数指针调用内联函数将不会导致内联式的函数调用(也就是不会将代码展开),由于编译器通常无法在编译器精确的确定会调用什么函数。

因此在调用点,编译器别无他法,仅仅好生成间接、非内联的函数调用代码。

条款15指向类成员的指针并不是指针

一个常规指针包括一个地址。假设解引用,就会得到位于该地址的对象。

与常规指针不同,一个指向成员的指针并不指向详细的内存位置。它指向的是一个类的特定成员,而不是指向一个特定对象里的特定成员。

通常最清晰的做法是将指向数据成员的指针看做是一个偏移量。但C++标准没有这样规定,仅仅是大多数编译器都将指向数据成员的指针实现为一个整数,当中包括被指向的成员的偏移量。另外加上1(加1是为了让值0能够表示一个空的数据成员指针。)这个偏移量告诉你。一个特定成员的位置距离对象的起点有多少字节。

一般来说,在C++中存在从指向派生类的指针到指向不论什么公有基类的提前定义转换。

在指向类成员的指针的情况下恰恰相反:存在从指向基类成员的指针到指向公有派生类成员的指针的隐式转换。但不存在从指向派生类成员的指针到指向其不论什么一个基类成员的指针的转换。

这个逆变性看起来有违直觉,只是,假设回顾指向数据成员的指针并不是一个对象的指针,而是对象内的一个偏移量,就会明确了。

class Shape{

Point center_;

};

class Circle : public{

double radius;

};

由于一个Circle也是一个Shape。所以一个Circle对象内包括一个Shape子对象。因而。Shape内的不论什么偏移量在Circle内也是一个有效的偏移量。

PointCircle::*loc = &Shape::center_;    //ok,从基类到派生类的转换

然而,一个Shape未必是一个Circle,因此一个Circle的成员的偏移量在Shape内未必是一个有效的偏移量。

doubleShape::*extent = &Circle::radius_;   //错误!

从派生类到基类的转换

16指向成员函数的指针并不是指针

和指向常规函数的指针不同,指向成员函数的指针能够指向一个常量成员函数。

和指向数据成员的指针的情形一样。为了对一个指向成员函数的桌子非常进行解引用,须要一个对象或一个指向对象的指针。

对于指向数据成员的指针的情形,为了訪问该成员,须要将对象的地址和成员的偏移量相加。对于指向成员函数的指针的情形,须要将地相的地址用作this指针的值,进行函数调用,以及其它用途。

和数据成员的指针一样,指向成员函数的指针也表现出一种逆变性。即存在从指向基类成员函数的指针到指向派生类成员函数指针的提前定义转换。反之则不然。

class B{

public:

void bset(int val){ bval_ = val;}

private:

int bval_;

};

class D : publicB{

public:

voiddset(int val){ dval _ = val;}

private:

int dval_;

};

B b;

D d;

void (B::*f1)(int)= &D::dset;    //错误!不存在这样的反向逆转

(b.*f1)(12);          //哎呀!訪问不存在的dval成员。

void (D::*f2)(int)= &B::bset;    //OK,存在这样的转换

(d.*f2)(11);          //OK。设置继承来的bval_数据成员

时间: 2024-12-29 10:12:01

C++必知必会(1)的相关文章

MySQL必知必会 学习笔记(一)

第一章  了解SQL 模式:   关于数据库和表的布局以及特性的信息.[描述表可以存储什么样的数据,数据如何分解,各部分信息如何命名等等,可以用来描述数据库中特定的表以及整个数据库(和其中表的关系)]. 第二章 MySQL简介 MySQL是一种DBMS,即它是一种数据库软件.基于客户机----服务器的数据库. MySQL工具: 1.mysql 命令行实用程序 2.MySQL Administrator 3.MySQL query Browser 第四章 检索数据 LIMIT 5 表示MySQL返

mysql 必知必会总结

以前 mysql 用的不是很多, 2 天看了一遍 mysql 必知必会又复习了一下基础.  200 页的书,很快就能看完, 大部分知识比较基础, 但还是了解了一些以前不知道的知识点.自己做一个备份,随时查看. 命令:sql 不区分大小写,语句大写,列.表名小写是一种习惯连接命令:mysql -u user_name –h example.mysql.alibabalabs.com –P3306 –pxxxxquithelp show; // 查看所有 show 命令show databases;

JSON必知必会学习总结(一)

七月第一周,从学校毕业回来上班的第一周.离开一段时候后,再次回来重新工作,有了很多新的认识,不再是实习时那么混混沌沌了.每天我自己该做什么,怎么做,做到什么程度更清晰了.除了要去完成我负责的工作,我开始去想除了完成工作我要从中获得什么. 今天早晨走的时候,随手塞包里一本薄薄的书--<JSON必知必会>,白天间隙的时候看了前两章,这两章设计的内容平时基本接触过,但是没有系统的总结过,看完之后清晰了很多. 首先,JSON是什么,这本书是说JSON是一种数据交换格式,被许多系统用于数据交换. 数据交

SQLServer:《SQL必知必会》一书的读书笔记(五)

第5课 高级数据过滤 5.1 组合 WHERE 子句 第4课介绍的 WHERE 子句在过滤数据时都是用单一的条件. 5.1.1 AND 操作符 检索由供应商 DLL01 制造且价格小于等于 4 美元的所有产品的名称和价格: SELECT prod_id, prod_price, prod_name FROM Products WHERE vend_id = 'DLL01' AND prod_price <= 4; 5.1.2 OR 操作符 检索任一个指定供应商制造的所有产品的名称和价格: SEL

.NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)

Microsoft.NET 解决方案,项目开发必知必会. 从这篇文章开始我将分享一系列我认为在实际工作中很有必要的一些.NET项目开发的核心技术点,所以我称为必知必会.尽管这一些列是使用.NET/C#来展现,但是同样适用于其他类似的OO技术平台,这些技术点可能称不上完整的技术,但是它是经验的总结,是掉过多少坑之后的觉醒,所以有必要花几分钟时间记住它,在真实的项目开发中你就知道是多么的有帮助.好了,废话不说了,进入主题. 我们在开发服务时为了调试方便会在本地进行一个基本的模块测试,你也可以认为是集

《MySQL必知必会》读书笔记_4

PS:一个实际的存储过程案例 CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_delete_article_by_id`(IN `id` int) BEGIN #Routine body goes here... DECLARE temp INT; SET @aid = id; SELECT COUNT(*) FROM gk_reply_article WHERE a_id = @aid INTO temp; IF(temp <> 0) THEN

移动前端开发人员必知必会:移动设备概述

因为工作岗位的变换带来工作内容的变动,对于移动网站的前端开发已经疏远了好几个月,在这好几个月中有很多新的东西出现,自己所掌握的一些东西也已经陈旧,所以选择了这本书<HTML5触摸界面设计与开发>来系统地学习和整理一下关于移动网站前端开发的知识体系. 之所以选择这本书,一是因为这本书比较新,2014年04月发的第一版.其二是因为作者Stephen Woods,这是Flickr团队的资深前端,Yahoo主页的Javascript技术平台正是出自此人之手. 接下来的时间里会陆续上传关于这本书学习的一

mysql学习--mysql必知必会1

?? 例如以下为mysql必知必会第九章開始: 正則表達式用于匹配特殊的字符集合.mysql通过where子句对正則表達式提供初步的支持. keywordregexp用来表示后面跟的东西作为正則表達式处理. (.)是正則表達式的一个符号,表示匹配随意一个字符: mysql> select prod_name -> from products -> where prod_name regexp '.000' -> order by prod_name; +--------------

《MySQL 必知必会》读书总结

这是 <MySQL 必知必会> 的读书总结.也是自己整理的常用操作的参考手册. ? ? 使用 MySQL 连接到 MySQL shell>mysql -u root -p Enter password:****** 显示数据库 mysql>SHOW DATABASES; 选择数据库 mysql>USE mytest; 显示数据库中的表 mysql>SHOW TABLES; 显示表列 mysql>SHOW COLUMNS FROM tmall_user; mysql

rime 必知必會

https://github.com/rime/home/wiki/CustomizationGuide Rime 定製指南 必知必會 建議您在定製 Rime 輸入法之前瞭解 Rime 輸入方案的概念.Rime 中的數據文件分佈及作用等基礎知識. 必知必會 重新佈署的操作方法 [中州韻]點擊輸入法狀態欄上的 ? (Deploy) 按鈕 或:如果找不到狀態欄,在終端輸入以下命令,可觸發自動部署: rm ~/.config/ibus/rime/default.yaml; ibus-daemon -d