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语言二分查找的简单应用

    一篇文章带你了解C语言二分查找的简单应用

    这篇文章主要介绍了二分查找算法在C语言程序中的使用示例,文中最后提到了使用二分查找法一个需要注意的地方,需要的朋友可以参考下
    2021-08-08
  • 解决C++ fopen按行读取文件及所读取的数据问题

    解决C++ fopen按行读取文件及所读取的数据问题

    今天小编就为大家分享一篇解决C++ fopen按行读取文件及所读取的数据问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • C++中函数的默认参数详细解析

    C++中函数的默认参数详细解析

    在函数声明或定义时,直接对参数赋值,该参数就是默认参数。在函数调用时,省略部分或全部参数,这时就会使用默认参数进行代替
    2013-10-10
  • 浅析栈区和堆区内存分配的区别

    浅析栈区和堆区内存分配的区别

    以下是对栈区和堆区内存分配的区别进行了详细的分析介绍,需要的朋友可以过来参考下
    2013-08-08
  • C/C++ 浅拷贝和深拷贝的实例详解

    C/C++ 浅拷贝和深拷贝的实例详解

    这篇文章主要介绍了C/C++ 浅拷贝和深拷贝的实例详解的相关资料,帮助大家理解这部分知识提供了基础知识及实例,需要的朋友可以参考下
    2017-08-08
  • C语言实现简单的猜数字游戏

    C语言实现简单的猜数字游戏

    这篇文章主要为大家详细介绍了C语言实现简单的猜数字游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • VC++实现输出GIF到窗体并显示GIF动画的方法

    VC++实现输出GIF到窗体并显示GIF动画的方法

    这篇文章主要介绍了VC++实现输出GIF到窗体并显示GIF动画的方法,需要的朋友可以参考下
    2014-07-07
  • C++11中的智能指针和垃圾回收使用

    C++11中的智能指针和垃圾回收使用

    本文主要介绍了C++11中的智能指针和垃圾回收使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • Opencv实现绿幕视频背景替换功能

    Opencv实现绿幕视频背景替换功能

    这篇文章主要为大家详细介绍了Opencv实现绿幕视频背景替换功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • 一篇文章带你掌握C++虚函数的来龙去脉

    一篇文章带你掌握C++虚函数的来龙去脉

    虚函数主要通过V-Table虚函数表来实现,该表主要包含一个类的虚函数的地址表,可解决继承、覆盖的问题,下面这篇文章主要给大家介绍了如何通过一篇文章带你掌握C++虚函数的来龙去脉,需要的朋友可以参考下
    2022-10-10

最新评论