Effective C++ 摘记(二)

2024-01-05 08:48
文章标签 c++ effective 摘记

本文主要是介绍Effective C++ 摘记(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


(四)、设计与声明

十八、让接口易用而不误用

类型一致性;


或者可以将 Day, Month, Year 定义为 类,来对输入的参数进行限制。

预防客户错误的另一个方法是,限制类型内什么事情可做,什么事情不可做。常见的限制是加上const, 例如 “以const修饰operator*的返回类型”可以防止客户因用户自定义类型而出错。 if (a * b = c) //愿意是 a*b == c, 如果使用const 修饰 运算符* 的返回类型,则会出现编译错误,从而阻止出错。

为了防止出现工厂模式返回的指针,由于客户疏忽没有被释放,使用 构造指资源的函数直接返回智能指针 shared_ptr 的方式。如:

shared_ptr防范跨DLL错误。

十九、设计class犹如设计type

11条准则。

(1)考虑新type的对象如何被构造和销毁

(2)考虑对象的初始化和对象的赋值有什么区别

(3)考虑新type的对象在使用过程中被 pass by value,其拷贝构造函数需要注意什么地方

(4)考虑新type的对象的私有成员的合法值,在构造函数中可以对其进行约束

(5)考虑新type的继承性能,是否需要将析构函数设置为virtual

(6)考虑新的type需要什么类型的转换,以便在类中实现类型转换函数

(7)考虑什么样的函数和操作符对新type而言是合理的

(8)考虑什么样的标准函数应该驳回,将这些函数设置为 private

(9)考虑什么是新type的“未声明接口”。它对效率、异常安全性以及资源运用提供何种保证。

(10)考虑新type是否足够一般化,若是,考虑定义为一个 class template,而不是一个class。

(11)考虑是否需要定义一个新的类型,或者只需要继承一个现成的类就可以了。


二十、常引用参数代替值传递

如果函数参数为 类的对象,则使用 pass-by-const-reference 比 pass-by-value更加有效。

void  test(const SimpleCalculator& c); //将对象引用声明为const可以避免在函数操作中对对象进行修改。

使用 const 对象引用作为参数,可以避免函数形参为父类,而实际传递实参为子类时造成的 参数切割。使得真正传递进函数的参数只是 父类部分。

如果函数参数为 内置数据类型(如 int, double等)或者 STL的迭代器或者 函数对象,则使用pass-by-value 更加有效。


二十一、需要返回对象时候不要返回引用

函数返回不要返回 stack 栈的局部变量或者heap堆的 全局或者静态变量都不要作为引用或者指针返回。

能返回对象,直接返回对象即可。

二十二、成员变量声明为private

两种访问权限:privateothers

protected并不比public封装性好。

二十三、用非成员函数和非友元函数替换成员函数

封装强度和改变强度成反比,因为只影响有限的用户;

类外访问函数封装性好于累内成员函数的封装性,不增加累内私有数据的访问函数的数量;

使用命名空间,使用 non-member函数来提高封装性。


宁可使用 non-member non-friend的函数来代替 member函数,这样可以增加封装性、包裹弹性和机能扩充性。



二十四、参数需要类型转换应使用非成员函数

针对二元运算符重载。

只有当参数位于参数列内,这个参数才是隐式转换的合格参与者。

class Rational {
public:Rational(int numerator = 0 ,int denominator = 1);int numerator() const;int denominator() const;const Rational operator* (const Rational& rhs) const;
private:
}

Rational   r;

Rational result = r* 2; //因为构造函数没有被声明为 explicit,故会进行隐式转换,将2转换为 Rational对象。

Ration result = 2 * r; //不会自动进行隐式转换,因为2 并不处于Rational 对象参数列表的位置。

为了支持交换运算,可以



如果需要对某个函数的所有参数(包括this 指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个 non-member.


二十五、没有异常的swap函数

类外构造特化的swap函数;

不要在swap的时候产生异常。


如果 swap 的缺省实现效率不足(这几乎总是意味着你的 class(类)或 template(模板)使用了 pimpl idiom 的某种变种),就按照以下步骤来做:

  1. 提供一个能高效地交换你的类型的两个 objects 的值的 public(公有)的 swap member function(成员函数)。出于我过一会儿就要解释的动机,这个函数应该永远不会抛出 exception(异常)。
  2. 在你的 class(类)或 template(模板)所在的同一个 namespace(名字空间)中提供一个 non-member(非成员)的 swap。用它调用你的 swap member function(成员函数)。

  3. 如果你写了一个 class(类)(不是 class template(类模板)),就为你的 class(类)特化 std::swap。让它也调用你的 swap member function(成员函数)
  4. namespace std {template<>                       // 全特化void swap<Widget>(Widget& a,     // std::swapWidget& b){a.swap(b);                     // <span style="color: rgb(255, 0, 0); font-family: Arial; line-height: 26px; ">不是 class template(类模板)),就为你的 class(类)特化 </span><span style="color: rgb(255, 0, 0); line-height: 26px; font-family: 'Courier New'; ">std::swap</span>}                                // swap member function
    }

最后,如果你调用 swap,请确保包含一个 using declaration 使 std::swap 在你的函数中可见,然后在调用 swap 时不使用任何 namespace(名字空间)限定。


(五)、实现

二十六、延后变量定义式

不要提前定义,直到使用改变量的前一刻为之;

针对循环内的对象需要根据构造析构与赋值的成本,以及可维护性进行权衡。




二十七、少做转型操作

Base(*this).virFun()只会影响对象的基类部分的数据副本,不会影响对象本身,如果使用指针类型转换则会无穷递归,去掉虚属性则消除类似问题;

用虚函数的特性代替dynamic_cast

尽量使用C++风格的转型。



二十八、避免返回对象内部数据的引用或指针

破坏了封装型;

函数返回对象析构导致空指针。

返回对象内部数据的引用或者指针,有可能会在外部对对象内部的数据进行修改,或者不经意删除对象内部的数据指针,造成内存错误。

如果函数返回 const的对象内部数据的引用,则可以一定程度上避免外部可能造成的对数据的修改。


函数返回对象析构导致空指针。例如:



二十九、异常安全的努力

对象管理资源;

copy-swap实现技术;

异常安全性取决于最弱安全保证的代码。



三十、inline里里外外

隐式:类内直接定义成(友)员函数,


显式:inline关键字;

由于inlining在大多数c++程序中是编译期间的行为,因此inline函数一般置于 头文件中。

template 通常也置于 头文件中,因为它一旦被使用,编译器为了将它具现化,需要知道长什么样子。

如果正在写一个template,且认为该template具体出来的所有函数都需要inlined,就需要将该template设置为inlined。

inline只是一个对编译器的申请,编译器可以拒绝。大多数编译器会拒绝执行太过复杂的inline,如递归等。同时如果函数中含有 virtual,则也会拒绝inline,因为virtual函数的调用是个动态的行为,只有在执行的时候才能够确定。

拒绝:复杂、虚函数、函数指针调用、模板、构造析构函数、影响动态连接或升级、对调试器的挑战(禁用)。

inline函数实际上没有函数地址,因为它被展开到调用处。如果inline函数发生改动,则使用该函数的程序都必须重新编译。


将大多数inlining限制在小型、被频繁调用的函数身上,这可使得日后的调试和二进制升级更容易,也可使得潜在的代码膨胀问题最小化,使得程序速度提升机会最大化。

不要只因为 function template出现在头文件中,就将他们声明为inline。


三十一、降低文件间编译依存关系

能使用引用和指针完成的不使用对象、用class声明代替定义,并提供不同的头文件——程序库文件和类定义头文件;

将接口Person类和实现类 PersonImpl 分离。在这样的设计下,Person的客户就完全与Dates, Addresses以及Person的实现细节分离了,那些classes的实现修改都不需要Person客户的重新编译,此外客户无法看到Person的实现细节,也不可能写出那些“取决于实现细节”的代码,这就是真正的“接口与实现分离”。

编译依存性最小化的本质: 用声明依存性替代实现依存性。让头文件尽可能自我满足。设计策略为:


handle classinterface class解除了接口与实现的耦合关系。

参考: http://blog.csdn.net/skc361/article/details/27977395


这篇关于Effective C++ 摘记(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/572318

相关文章

Windows下C++使用SQLitede的操作过程

《Windows下C++使用SQLitede的操作过程》本文介绍了Windows下C++使用SQLite的安装配置、CppSQLite库封装优势、核心功能(如数据库连接、事务管理)、跨平台支持及性能优... 目录Windows下C++使用SQLite1、安装2、代码示例CppSQLite:C++轻松操作SQ

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元