Effective C++ 学习笔记

 更新时间:2023年08月10日 10:48:42   作者:SLN  
这篇文章主要介绍了Effective C++ 学习笔记,想学习Effective C++的朋友可以参考一下

条款 01:视C++为一个语言联邦

  • C++的次语言:

    • C
    • Object-Oriented C++
    • Template C++
    • STL
  • C++的编译流程:
    C++代码的编译流程通常包括了多个阶段,从源代码到可执行程序的生成。下面是一个简要的C++代码编译流程的概述:

    1. 预处理(Preprocessing):
       - 在这个阶段,编译器会处理所有的预处理指令,例如 `#include`、`#define` 等,以及删除注释。
       - 预处理指令的处理会生成一个经过预处理的源代码文件。

    2. 编译(Compilation):
       - 经过预处理的源代码会被编译器转换为汇编语言代码(通常是中间表示形式)。
       - 编译阶段主要负责检查语法错误和类型错误,并生成对应的中间表示文件。

    3. 汇编(Assembly):
       - 在这个阶段,汇编器将中间表示的代码转换为机器代码,生成目标文件(通常是以 `.obj` 或 `.o` 为扩展名)。
       - 目标文件包含了计算机可执行的二进制代码和相关的元信息。

    4. 链接(Linking):
       - 当你的程序使用了多个源文件或库文件时,这些目标文件需要被链接在一起,生成最终的可执行程序。
       - 链接器会解决函数调用、变量引用等,并将不同目标文件中的代码和数据合并。
       - 最终的可执行文件就是由链接器生成的。

    5. 加载(Loading)(可选):
       - 如果你的操作系统需要,可执行文件会被加载到内存中,准备运行。
       - 这一步骤通常由操作系统完成。

    6. 运行(Execution):
       - 可执行程序在内存中运行,执行其中的代码,产生相应的计算结果。

需要注意的是,这个流程可能在不同的编译器和操作系统上有所不同。另外,现代的编译器和开发环境通常会在这些阶段中进行优化,以提高代码的性能和效率。

条款 02:尽量以const, enum, inline替换 #define

  • #define是一个预处理指令,用于创建一个简单的宏定义。它允许你在代码中为一个特定的标识符(通常是一个变量名或常量,通常大写)定义一个文本替换。当代码被编译前的预处理阶段处理时,所有使用这个宏定义的地方都会被替换为指定的文本。
    缺点: 可能导致代码可读性下降、类型不匹配的问题、难以调试等。在现代C++中,倾向于使用类型安全的常量、枚举、内联函数以及更高级的抽象来取代宏,以提高代码的可维护性和可读性。
#define PI 3.14159
  • constC++ 中的“类专属常量”(Class-specific Constants)通常是指在类内部定义的常量。这些常量在类的作用域内可见,只能通过类名访问,而不能通过类的对象访问。它们可以在类的任何成员函数中使用,无需实例化对象。
    通常情况下,类专属常量会使用 static 关键字来定义,因为它们属于类而不是类的实例。定义为 static 的常量将在所有类的实例之间共享,且只存在一份副本,可以节省内存。
#include <iostream>
class MyClass {
public:
    static const int classConstant = 42; // 类专属常量
    static const double pi; // 声明,定义在类外部
    void printClassConstant() {
        std::cout << "Class constant: " << classConstant << std::endl;
    }
};
const double MyClass::pi = 3.1415926; // 在类外部定义类专属常量
int main() {
    MyClass obj;
    obj.printClassConstant(); // 调用类专属常量的成员函数
    std::cout << "Pi: " << MyClass::pi << std::endl; // 通过类名访问类专属常量
    return 0;
}
  • enum在 C++ 中,非静态成员变量(例如 Array)不能使用类的静态成员变量(例如 ConstNumber)作为数组大小。在编译时,数组大小必须是一个在编译期就可以确定的常量表达式。
//错误的,ConstNumber 虽然是类的静态常量,但是它在编译期是无法确定的,因此不能用作数组大小。
class ANonDefine
{
public:
	static const int ConstNumber;
	 int Array[ConstNumber];
};

解决方法:

在ConstNumber声明时就赋值。

使用enum

class ANonDefine
{
public:
	enum {ArraySize=5};
	int Array[ArraySize];
};
  • inline宏函数容易出错,可以使用inline代替
#include <iostream>
#define MAX_MACRO(a, b) ((a) >= (b) ? (a) : (b))
inline int max_inline(int a, int b) {
    return (a >= b) ? a : b;
}
int main() {
    int x = 5, y = 6;
    int result_macro = MAX_MACRO(++x, y); // 使用宏,产生不同的结果
    x = 5; y = 6; // 正确的变量赋值
    int result_inline = max_inline(++x, y); // 使用内联函数,产生不同的结果
    std::cout << "Macro result: " << result_macro << std::endl; //7
    std::cout << "Inline result: " << result_inline << std::endl;//6
    system("pause");
    return 0;
}

条款 03:尽可能使用const

  • const 是一个关键字,用于指定变量、函数参数、函数返回类型等为常量。const 关键字的使用可以在代码中增加类型安全性,并帮助防止对变量进行意外的修改
// const出现在*左边,表示被指物是常量,出现在*右边,表示指针自身是常量
const int x = 5;  // 声明一个不可修改的整数常量
const int* ptr = &x;  // 声明一个指向常量的指针,指针指向的常量不可修改
int const * ptr = &x;  // 声明一个指向常量的指针,指针指向的常量不可修改
int y = 10;
int* const ptr = &y;  // 声明一个指针常量,指针不可修改
const int* const ptr = &y;  // 指针及其指向的常量都不可修改
  • stl 中的 conststl 的迭代器基础是指针,所以迭代器的作用就像个T *指针。
    声明迭代器为 const 就像 T * const。表示指针不改变,可以改内容。
    如果希望迭代器所指的东西不可改变,const_iterator代替iterator,表示指针可变,不可修改内容。
std::vector<int>Vector;
for(int i=0;i<10;++i)
{
    Vector.push_back(i);
}
const std::vector<int>::iterator Iterator=Vector.begin();
*Iterator=10;//所指物可以修改
//Iterator++;迭代器不可修改
std::vector<int>::const_iterator ConstIterator=Vector.begin();
//*ConstIterator=10;所指物不可修改
ConstIterator++;//指针可以修改
for (auto i=ConstIterator;i!=Vector.end();++i)
{
	FFunctionLibrary::Println(*i);
}
  • const成员函数在成员函数声明和定义的末尾,使用 const 关键字来表示这是一个常量成员函数。
    在常量成员函数中,不能修改类的非静态成员变量,包括类的数据成员和普通成员函数。
    常量对象(通过 const 关键字声明的对象)只能调用常量成员函数。非常量对象可以调用常量成员函数。
    const 成员函数的返回类型是否加上 const 关键字会影响返回值的常量性,如果 const 成员函数的返回类型不加上 const 关键字,那么返回的值被修改。如果 const 成员函数的返回类型加上 const 关键字,那么返回的值将被视为常量,不允许修改,只能读取。
    C++允许在类中同时定义常量和非常量版本的同名函数,它们可以通过对象的常量性来区分。这被称为函数的 const 重载。const 类对象调用 const 成员函数,non-const 类对象调用普通成员函数。
#include <iostream>
class MyClass {
public:
    void printValue() {
        std::cout << "Non-const function: " << value << std::endl;
    }
    void printValue() const {
        std::cout << "Const function: " << value << std::endl;
    }
    void setValue(int newValue) {
        value = newValue;
    }
private:
    int value = 0;
};
int main() {
    MyClass obj;
    const MyClass constObj;
    obj.setValue(42);
    obj.printValue();      // 调用非常量成员函数
    constObj.printValue(); // 调用常量成员函数
    return 0;
}
  • mutablemutable 用于修饰类的非静态成员变量,在常量成员函数内部允许对这些变量进行修改,即使对象被标记为 const。
    使用 mutable 可以在常量成员函数中实现对某些状态的修改,而不影响常量性的约束。
class MyClass {
public:
    int getValue() const; // 声明常量成员函数
private:
    mutable int count;   // 声明一个可变成员变量
};
int MyClass::getValue() const {
    // 在常量成员函数内修改可变成员变量
    count++;

到此这篇关于Effective C++ 学习笔记的文章就介绍到这了,更多相关Effective C++内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ I/O文件读写操作的示例代码

    C++ I/O文件读写操作的示例代码

    这篇文章主要介绍了C++ I/O文件读写操作的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • C++中的异常处理机制详解

    C++中的异常处理机制详解

    本文给大家分享的是C++中的异常处理机制。对如何处理异常、基本异常语法、异常保护代码等进行了探讨,推荐给大家。
    2017-04-04
  • C++之向下取整(>>)与向零取整(/)用法

    C++之向下取整(>>)与向零取整(/)用法

    C++中向下取整(floor)和向0取整(trunc)在负数处理上存在差异,前者向负无穷靠拢,后者截断小数,需根据场景选择,如二分查找用向0取整,数值映射需floor,注意整数除法默认向0取整,位运算对负数为floor,避免因取整方式导致逻辑错误
    2025-09-09
  • STL list链表的用法详细解析

    STL list链表的用法详细解析

    这篇文章是关于C++语言的一个新的扩展——标准模板库的(Standard Template Library),也叫STL
    2013-09-09
  • C++自旋锁的实现示例

    C++自旋锁的实现示例

    自旋锁是一种非阻塞锁,线程在获取锁失败时会忙等待而不是挂起,它适用于锁持有时间极短的场景,可以在用户态运行,避免系统调用开销,下面就来详细的介绍一下C++自旋锁的使用,感兴趣的可以了解一下
    2026-02-02
  • 在C++中自定义宏的简单方法

    在C++中自定义宏的简单方法

    这篇文章主要介绍了在C++中自定义宏的简单方法,作者建议使用类似定义函数一样的方法来定义宏,需要的朋友可以参考下
    2015-07-07
  • C++函数返回双值的几种方法

    C++函数返回双值的几种方法

    本文介绍了在C++和Qt开发中返回两个double值的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-01-01
  • 在C语言编程中使用变量的基础教程

    在C语言编程中使用变量的基础教程

    这篇文章主要介绍了在C语言编程中使用变量的基础教程,特别需要注意C语言中的指针变量,需要的朋友可以参考下
    2016-02-02
  • 用C语言的泛型实现交换两个变量值

    用C语言的泛型实现交换两个变量值

    在日常编程里面经常会遇到交换两个变量的内容的任务,对于泛型类型而言有两种泛型策略来实现,下面跟着小编一起来学习学习。
    2016-08-08
  • 详解C语言中数据的存储

    详解C语言中数据的存储

    这篇文章主要为大家介绍了C语言中数据的存储,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11

最新评论