条款26:尽可能延后变量定义式的出现时间

  • C++推荐在使用对象前才定义对象(调用构造函数赋初值)
  • 只在循环中使用的变量定义在循环内部(除非"赋值"成本低于"构造+析构"成本)

条款27:尽量少做转型动作

  • 旧式风格转型

    • C风格转型 \((T)expression\)
    • 函数风格转型 \(T(expression)\)
  • C++四种新式转型(new-style 或 C++-style cases)
    • const_cast(expression) 移除对象常量性(cast away the constness)
    • dynamic_cast(expression) 安全向下转型(safe downcasing)
    • reinterpret_cast(expression) 低级转型
    • static_cast(expression) 强迫隐式转型(implicit conversions)
  • 尽量避免转型(特别是dynamic_cast)
#include <iostream>
#include <string>
#include <memory> using namespace std; class base {
public:
virtual void type() {cout << "base" << endl;}
}; class drive : public base {
public:
drive( double d) : dou(d) {}
virtual void type() {cout << "drive" << endl;} void show() {
cout << dou << endl;
} private:
double dou;
}; int main() {
shared_ptr<base> b = shared_ptr<base>(new drive(1.2));
shared_ptr<drive> d = dynamic_pointer_cast<drive>(b);
d->show();
}

改写成

#include <iostream>
#include <string>
#include <memory> using namespace std; class base {
public:
virtual void type() {cout << "base" << endl;}
virtual void show() {}
}; class drive : public base {
public:
drive( double d) : dou(d) {}
virtual void type() {cout << "drive" << endl;} virtual void show() {
cout << dou << endl;
} private:
double dou;
}; int main() {
shared_ptr<base> b = shared_ptr<base>(new drive(1.2));
b->show();
}
  • 使用C++新式转型,而非使用旧式转型

条款28:避免返回handles指向对象内部成分

  • 避免返回指向对象内部成员的handles(包括references,指针,迭代器)

条款29:为“异常安全”而努力是值得的

  • "异常安全函数"承诺即使发生异常也不会有资源泄漏或数据结构的破坏。

    • 基本保证:如果抛出异常,程序仍然保持有效状态
    • 强烈保证:如果抛出异常,程序状态恢复到调用前
    • 不抛异常:内置类型的操作就绝不会抛出异常

条款30:透彻了解inlining的里里外外

  • inline的申请方式

    • 隐喻方式——将函数定义于class内(包括定义域class的友元函数)
    • 声明方式——函数定义式前加关键字inline
  • inline只是个申请,编译器可以忽略
    • 大部分编译器拒绝inline太过复杂的函数(带有循环或递归的函数)
    • 所有调用virtual函数(除非是平淡无奇的)
  • 不要把构造函数和析构函数申请为inline
  • inline应该设置在小型,频繁调用的函数身上

条款31:将文件间的编译依存关系降至最低

  • 用 "声明的依赖" 替换 "定义的依赖"(让头文件尽可能自我满足,如果做不到就和其他文件的声明式相依)

    • 使用object references 或 object pointers 可以完成的任务,就不要使用objects 
    • 如果能够,尽量以class的声明式替换class的定义式
    • 为声明式提供不同的头文件
  • Handle classes
    • Handler Classes中将变量换成变量的地址(指针),头文件只给出具体的class xxx的声明,而在cpp里面才c具体lass的实现
    • 由此Handler Classes只暴露出接口,并隐藏数据结构
//Person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <memory>
using namespace std;
class PersonImp;
class Person
{
public:
Person(const string& na);
string GetName() const; private:
shared_ptr<PersonImp> MemberImp;
}; #endif // PERSON_H
//Person.cpp
#include "Person.h"
class PersonImp
{
public:
PersonImp(string na) : Name(na){} string GetName() const {
return Name;
}
private:
string Name;
}; Person::Person(const string& na) : MemberImp(new PersonImp(na)) {
} string Person::GetName() const
{
return MemberImp->GetName();
}
//main.cpp
#include <iostream>
#include <string>
#include "Person.h" int main() {
Person p("xiao ming");
cout << p.GetName() << endl;
}
  • Interface classes(抽象类)

    • 利用多态,在父类抽象类中定义接口,并利用静态函数(static creat)返回具体对象
    • 抽象类暴露接口,并隐藏数据结构等
//Persion.cpp
#include "Person.h"
class RealPerson : public Person {
public:
RealPerson(const string& na) : name(na) {}
virtual string GetName() const {
return name;
} private:
string name;
}; shared_ptr<Person> Person::creat(const string &na) {
return shared_ptr<Person>(new RealPerson(na));
}
//Person.h
#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <memory>
using namespace std;
class Person
{
public:
static shared_ptr<Person> creat(const string& na); virtual string GetName() const = 0;
}; #endif // PERSON_H
//main.cpp
#include <iostream>
#include <string>
#include "Person.h" int main() {
shared_ptr<Person> p = Person::creat("xiaoming");
cout << p->GetName() << endl;
}

《Effective C++》实现:条款26-条款31的更多相关文章

  1. EC读书笔记系列之14:条款26、27、28、29、30、31

    条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...

  2. More Effective C++ 基础议题(条款1-4)总结

    More Effective C++ 基础议题(条款1-4)总结 条款1:仔细区别pointers和references 如果有一个变量,其目的是用来指向(代表)另一个对象,但是也有可能它不指向(代表 ...

  3. Effective Modern C++翻译(4)-条款3:了解decltype

    条款3 了解decltype decltype是一个有趣的东西,给它一个变量名或是一个表达式,decltype会告诉你这个变量名或是这个表达式的类型,通常,告诉你的结果和你预测的是一样的,但是偶尔的结 ...

  4. Effective Modern C++翻译(2)-条款1:明白模板类型推导

    第一章 类型推导 C++98有一套单一的类型推导的规则:用来推导函数模板,C++11轻微的修改了这些规则并且增加了两个,一个用于auto,一个用于decltype,接着C++14扩展了auto和dec ...

  5. Effective Modern C++翻译(5)-条款4:了解如何观察推导出的类型

    条款4:了解如何观察推导出的类型 那些想要知道编译器推导出的类型的人通常分为两种,第一种是实用主义者,他们的动力通常来自于软件产生的问题(例如他们还在调试解决中),他们利用编译器进行寻找,并相信这个能 ...

  6. 《Effective Modern C++》翻译--条款4:了解怎样查看推导出的类型

    条款4:了解怎样查看推导出的类型 那些想要了解编译器怎样推导出的类型的人通常分为两个阵营. 第一种阵营是实用主义者.他们的动力通常来自于编敲代码过程中(比如他们还在调试解决中),他们利用编译器进行寻找 ...

  7. 《Effective C++ 》学习笔记——条款11

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  8. 《Effective C++》条款26 防卫潜伏的ambiguity模棱两可的状态

    每个人都有思想.有些人相信自由经济学,有些人相信来生.有些人甚至相信COBOL是一种真正的程序设计语言.C++也有一种思想:它认为潜在的二义性不是一种错误.ambiguity 这是潜在二义性的一个例子 ...

  9. Effective C++ -----条款26:尽可能延后变量定义式的出现时间

    尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率.

随机推荐

  1. Java与.net的选择和比较

    跨平台对开发商是一个巨大的诱惑.一次开发,多个平台使用,降低了迁移成本,有利.但Java的开发工具没有.net顺手,对编码人员的要求比.net要高. .net培训成本低,上手快.尤其如果开发人员以前都 ...

  2. struct的匿名用法详解

    Go只提供类型而不用写字段名的方式,也就是匿名字段,也称为嵌入字段. 当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct. 举个例子,看 ...

  3. input中只能写入数字int、float

    input 属性 type="number" <input type="number" min="1" max="100&q ...

  4. html初步学习

    ①:<meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0,minimum-scale ...

  5. 自定义控制台程序导出角色对实体的权限为Excel文件

    本人微信公众号:微软动态CRM专家罗勇 ,回复282或者20181116可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 先上 ...

  6. 如何使用apache的ab压力测试小工具传参数

    前言: windows下安装的phpstudy软件里集成的apache带了ab工具,所以可以不用单独下载.其他的操作系统下的安装或部署这里就不介绍了! 一. 使用windows的cmd进入apache ...

  7. Android网络图片转换成bitmap保存到本地指定文件夹

    下列代码,请求网络图片转换为bitmap,然后保存到指定文件夹,微信,QQ分享,要求缩略图不大于32kb 压缩图片代码,使用了Glide来进行图片压缩处理 Glide.get(ShopDetailsA ...

  8. (最简单)红米手机5A的USB调试模式在哪里开启的方法

    当我们使用安卓手机链接Pc的时候,或者使用的有些APP比如我们公司营销小组当使用的APP引号精灵,之前使用的老版本就需要开启usb调试模式下使用,现当新版本不需要了,如果手机没有开启usb调试模式,P ...

  9. SQLServer之事务简介

    事务定义 事务是单个的工作单元.事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序自动执行. 事务分类 自动提交事务 每条单独的语句都是一个事务. 在自动提 ...

  10. SQLServer之创建LOGON触发器

    LOGON触发器工作原理 登录触发器将为响应 LOGON 事件而激发存储过程. 与 SQL Server实例建立用户会话时将引发此事件. 登录触发器将在登录的身份验证阶段完成之后且用户会话实际建立之前 ...