类与对象知识总结+封闭类+const+this指针 C++程序设计与算法笔记总结(三) 北京大学 郭炜(下)

简介: 类与对象知识总结+封闭类+const+this指针 C++程序设计与算法笔记总结(三) 北京大学 郭炜(下)

常量成员函数

如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加 const关键字。

常量成员函数(const member function)是指在类中声明的成员函数,在其声明末尾添加const关键字。常量成员函数承诺不会修改对象的状态,因此它们不能修改类的非静态成员变量,也不能调用非常量成员函数(除非这些成员函数也被声明为常量成员函数)。

常量成员函数对于处理只读操作或者保护数据的完整性很有用,因为它们可以确保在使用常量对象或通过常量引用/指针访问对象时,不会意外地修改对象的状态。

下面是一个示例代码:

class MyClass {
private:
    int data;
public:
    int getValue() const {
        // 这是一个常量成员函数,不能修改成员变量
        return data;
    }
    void setValue(int value) {
        // 非常量成员函数可以修改成员变量
        data = value;
    }
};

在上述示例中,getValue()被声明为常量成员函数,因此它不能修改data成员变量的值。而setValue()是非常量成员函数,可以修改data成员变量。

当你有一个常量对象时,只能调用常量成员函数来访问其成员变量和执行操作。例如:

int main() {
    const MyClass obj;
    int value = obj.getValue();  // 可以调用常量成员函数
    // obj.setValue(10);  // 错误,常量对象无法调用非常量成员函数
    return 0;
}

需要注意的是,在常量成员函数中不能修改成员变量,也不能调用非常量成员函数,除非这些非常量成员函数也被声明为常量成员函数。

常量成员函数在类中声明的成员函数末尾添加const关键字。它们承诺不会修改对象的状态,因此对于只读操作或保护数据完整性很有用。常量成员函数可以在常量对象或通过常量引用/指针访问对象时调用,并且不能修改成员变量或调用非常量成员函数(除非这些成员函数也被声明为常量成员函数)。

当使用常量成员函数时,还需要注意以下几点:

  1. 常量对象调用:常量对象只能调用常量成员函数。这是因为常量对象被视为不可修改的,所以只能使用常量成员函数来访问对象的状态。
  2. 重载:常量成员函数和非常量成员函数可以进行重载。如果有两个成员函数,一个是常量成员函数,另一个是同名的非常量成员函数,它们可以根据调用对象的常量性来区分。
class MyClass {
public:
    int getValue() const {
        // 常量成员函数
        return 10;
    }
    int getValue() {
        // 非常量成员函数
        return 20;
    }
};
int main() {
    const MyClass obj1;
    MyClass obj2;
    int value1 = obj1.getValue();  // 调用常量成员函数
    int value2 = obj2.getValue();  // 调用非常量成员函数
    return 0;
}
  1. 返回类型:常量成员函数可以返回实际值,也可以返回常量引用或指针。如果返回一个非常量类型的实际值,它会被复制到调用者的副本中;如果返回常量引用或指针,则避免了无谓的复制。
  2. mutable关键字:在常量成员函数中,如果希望修改某些成员变量,可以使用mutable关键字来修饰这些成员变量。被mutable修饰的成员变量可以在常量成员函数中被修改。
class MyClass {
private:
    mutable int cacheValue;
public:
    int getValue() const {
        if (cacheValue == 0) {
            // 计算并缓存值
            cacheValue = calculateValue();
        }
        return cacheValue;
    }
    int calculateValue() const {
        // 计算值的逻辑
        return 42;
    }
};

在上述示例中,cacheValue成员变量被声明为mutable,因此可以在常量成员函数中更新它的值。

常量成员函数在保护对象状态的同时,也提供了对只读操作的方便访问。通过合理使用常量成员函数,可以增强代码的安全性和可靠性,并遵循面向对象设计的原则。

常量成员函数是指在类中声明的成员函数末尾添加const关键字。它们只能用于常量对象或通过常量引用/指针访问对象,并且不能修改成员变量或调用非常量成员函数(除非这些成员函数也被声明为常量成员函数)。常量成员函数可以进行重载,返回实际值、常量引用或指针,并且可以使用mutable关键字修饰某些成员变量以在常量成员函数中进行修改。

如果一个成员函数中没有调用非常量成员函数,也没有修改成员变量的值,那么,最好将其写成常量成员函数。

对C++中const的说明

在C++中,const是一个关键字,用于指定对象或变量是只读的,即不可修改。它可以应用于不同的上下文中,包括:

  1. 对象和变量声明:通过在变量或对象的声明前加上const关键字,可以将其标记为只读。这意味着一旦被初始化,就不能再修改该对象或变量的值。
const int x = 10; // 声明一个只读的整数常量x
const MyClass obj; // 声明一个只读的MyClass对象
  1. 函数参数:使用const关键字修饰函数参数,表示该参数在函数内部是只读的,在函数执行过程中不能被修改。
void print(const std::string& str) {
    // 该函数不能修改str的内容
    std::cout << str << std::endl;
}
  1. 成员函数:在成员函数后面添加const关键字,表示该成员函数是一个常量成员函数。常量成员函数承诺不会修改对象的状态,并且只能调用其他常量成员函数或访问类的只读成员变量。
class MyClass {
public:
    void foo() const {
        // 这是一个常量成员函数
        // 不能修改成员变量或调用非常量成员函数
    }
};
  1. 返回类型:const关键字也可以用于指定函数或操作符的返回类型是只读的。
const int calculateValue() {
    // 返回一个只读的整数值
    return 42;
}
const MyClass operator+(const MyClass& obj) const {
    // 返回一个只读的MyClass对象
    // 不能修改当前对象或调用非常量成员函数
}

const关键字对于增强代码的可读性、安全性和可维护性非常有帮助。它可以避免意外的修改,保护数据的完整性,并提供了更好的接口设计和封装性。

需要注意的是,使用const关键字并不意味着该对象或变量在内存中是只读的,而仅仅表示在代码中对其进行修改是不被允许的。

当使用const关键字时,还有一些细节和注意事项需要考虑:

  1. 可以重载非constconst成员函数:在同一个类中,可以同时定义一个非const版本和一个const版本的成员函数。这样,在调用对象为常量或非常量时,编译器会根据调用对象的常量性选择相应的成员函数。
class MyClass {
public:
    void foo() {
        // 非const 版本的成员函数
    }
    void foo() const {
        // const 版本的成员函数
    }
};
  1. 常量对象只能调用常量成员函数:常量对象只能调用常量成员函数,因为常量对象被视为只读对象,不允许修改其状态。但非常量对象可以调用常量成员函数和非常量成员函数。
void someFunction(const MyClass& obj) {
    obj.foo();  // 可以调用常量成员函数
    MyClass nonConstObj;
    nonConstObj.foo();  // 也可以调用非常量成员函数
}
  1. 返回类型是const的影响:如果函数返回类型是const,则返回的值通常不能被修改。
const int getValue() {
    return 42;  // 返回的值是只读的
}
int main() {
    const int value = getValue();
    // value = 10;  // 错误,value是只读的
    return 0;
}
  1. 指针和引用的const:当使用指针或引用时,const关键字可以应用于指针本身或指向的对象。这样可以限制对指针或引用的修改,或者限制被指向的对象的修改。
int x = 10;
const int* ptr = &x;  // 指向常量的指针,不能通过ptr修改x的值
int y = 20;
int* const ref = &y;  // 指向整数的常量指针,不能通过ref修改指针的指向
  1. mutable成员变量:mutable关键字可以用于修饰类的成员变量,它表示该成员变量可以在常量成员函数中被修改。
class MyClass {
private:
    mutable int count;
public:
    void increment() const {
        ++count;  // 在常量成员函数中可以修改mutable成员变量
    }
};

需要注意的是,const关键字应根据需要和语义正确地应用。它可以提高代码的可读性、安全性和可维护性,但也需要谨慎使用以避免过度使用。正确使用const关键字可以帮助捕捉编程错误、保护数据完整性,并提供更好的接口设计和封装性。

当使用const关键字时,还有一些概念和技巧需要了解:

  1. 保证线程安全性:在多线程环境中,常量对象的成员函数是线程安全的。由于常量对象的状态不会被修改,多个线程可以同时访问常量对象的成员函数而无需额外的同步机制。
  2. 常量性转换:常量性可以通过类型转换来进行转换。即可以将非常量对象转换为常量对象进行只读操作。这通过将对象引用或指针的类型从非常量改变为常量来实现。
void func(const MyClass& obj) {
    // 可以接受常量对象作为参数并进行只读操作
}
int main() {
    MyClass obj;
    const MyClass& constRef = obj;  // 将非常量对象转换为常量引用
    const MyClass* constPtr = &obj;  // 将非常量对象的地址转换为常量指针
    return 0;
}
  1. const和函数重载:常量性可以用作函数重载的条件之一。如果一个函数的参数是常量对象或常量引用,那么可以重载该函数以提供对常量对象的特殊处理。
class MyClass {
public:
    void process() {
        // 非const 版本的成员函数
    }
    void process() const {
        // const 版本的成员函数
    }
};
int main() {
    MyClass obj;
    const MyClass constObj;
    obj.process();      // 调用非const版本的process函数
    constObj.process(); // 调用const版本的process函数
    return 0;
}
  1. const修饰符位置:在函数声明中,const关键字可以放在成员函数的后面,也可以放在参数列表的后面。这两种形式的意义是相同的,但通常将const关键字放在函数后面更为常见。
class MyClass {
public:
    void process() const;   // const放在函数后面
    void update() const;    // const放在参数列表后面
};
void MyClass::process() const {
    // const成员函数的实现
}
void MyClass::update() const {
    // const成员函数的实现
}

需要根据具体情况正确使用const关键字。合理使用const可以增强代码的安全性、可读性和可维护性,并帮助捕捉编程错误。它提供了一种约束机制,用于指定只读操作和不会修改对象状态的函数,从而增加了代码的健壮性和可靠性。

常量成员函数的重载

在C++中,常量成员函数可以根据被调用对象的常量性进行重载。这意味着可以定义一个非常量版本和一个常量版本的成员函数,分别用于处理常量对象和非常量对象。

下面是一个示例代码:

class MyClass {
public:
    void foo() {
        // 处理非常量对象的逻辑
        std::cout << "Non-const version" << std::endl;
    }
    void foo() const {
        // 处理常量对象的逻辑
        std::cout << "Const version" << std::endl;
    }
};
int main() {
    MyClass obj1;
    const MyClass obj2;
    obj1.foo();  // 调用非常量版本的foo函数
    obj2.foo();  // 调用常量版本的foo函数
    return 0;
}

在上述示例中,MyClass类定义了两个名为foo()的成员函数,一个是非常量版本,另一个是常量版本。当调用非常量对象obj1foo()函数时,会调用非常量版本;而当调用常量对象obj2foo()函数时,会调用常量版本。

通过使用常量成员函数的重载,可以根据对象的常量性来选择合适的操作方式。这样可以保证对常量对象的只读操作以及非常量对象的修改操作都能得到正确的处理。

需要注意的是,常量成员函数的重载不仅与常量性有关,还与函数的参数类型和数量相关。因此,在进行函数重载时,需要确保函数的签名(包括参数类型、常量性等)是不同的。

总结一下,常量成员函数可以根据对象的常量性进行重载,以提供对常量对象和非常量对象的不同处理。通过合理使用常量成员函数的重载,可以保证对象在不同常量性下得到适当的操作,并增加代码的灵活性和可读性。

mutable成员变量(可以在const成员函数中修改的成员变量)

可以在const成员函数中修改的成员变量

在C++中,mutable关键字用于修饰类的成员变量,它表示该成员变量可以在常量成员函数中被修改,即使这些函数通常是不允许修改对象状态的。

下面是一个示例代码:

class MyClass {
private:
    mutable int count;
public:
    void increment() const {
        ++count;  // 在常量成员函数中可以修改mutable成员变量
    }
};

在上述示例中,count成员变量被声明为mutable,这意味着即使在常量成员函数(如increment())中,也可以对其进行修改。默认情况下,常量成员函数是不允许修改对象的状态的,但使用mutable关键字可以打破这个限制。

mutable关键字适用于那些在实现细节中需要跟踪或缓存信息的成员变量。例如,在某个类中计算并缓存某个值,而不希望每次调用时都重新计算,可以使用mutable来标记该成员变量。

需要注意以下几点:

  • mutable只能应用于非静态成员变量,因为静态成员变量是与类而不是对象相关联的。
  • mutable成员变量的修改仅限于同一对象内部,并不会影响其他对象的状态。
  • 尽管mutable允许在常量成员函数中修改变量,但仍应该谨慎使用。这是因为常量成员函数通常被认为是不会引起对象状态变化的,因此对于需要修改的情况,最好考虑其他可行的设计方案。

总结一下,mutable关键字用于修饰类的成员变量,表示该成员变量可以在常量成员函数中被修改。它在某些情况下提供了更灵活的设计选择,但也应该谨慎使用,以避免滥用导致代码逻辑混乱或违背设计原则。

目录
相关文章
|
2月前
|
存储 编译器 C语言
【c++丨STL】string类的使用
本文介绍了C++中`string`类的基本概念及其主要接口。`string`类在C++标准库中扮演着重要角色,它提供了比C语言中字符串处理函数更丰富、安全和便捷的功能。文章详细讲解了`string`类的构造函数、赋值运算符、容量管理接口、元素访问及遍历方法、字符串修改操作、字符串运算接口、常量成员和非成员函数等内容。通过实例演示了如何使用这些接口进行字符串的创建、修改、查找和比较等操作,帮助读者更好地理解和掌握`string`类的应用。
57 2
|
2月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
109 5
|
2月前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
107 4
|
8天前
|
机器学习/深度学习 算法
基于改进遗传优化的BP神经网络金融序列预测算法matlab仿真
本项目基于改进遗传优化的BP神经网络进行金融序列预测,使用MATLAB2022A实现。通过对比BP神经网络、遗传优化BP神经网络及改进遗传优化BP神经网络,展示了三者的误差和预测曲线差异。核心程序结合遗传算法(GA)与BP神经网络,利用GA优化BP网络的初始权重和阈值,提高预测精度。GA通过选择、交叉、变异操作迭代优化,防止局部收敛,增强模型对金融市场复杂性和不确定性的适应能力。
134 80
|
1天前
|
机器学习/深度学习 算法
基于遗传优化的双BP神经网络金融序列预测算法matlab仿真
本项目基于遗传优化的双BP神经网络实现金融序列预测,使用MATLAB2022A进行仿真。算法通过两个初始学习率不同的BP神经网络(e1, e2)协同工作,结合遗传算法优化,提高预测精度。实验展示了三个算法的误差对比结果,验证了该方法的有效性。
|
4天前
|
机器学习/深度学习 数据采集 算法
基于PSO粒子群优化的CNN-GRU-SAM网络时间序列回归预测算法matlab仿真
本项目展示了基于PSO优化的CNN-GRU-SAM网络在时间序列预测中的应用。算法通过卷积层、GRU层、自注意力机制层提取特征,结合粒子群优化提升预测准确性。完整程序运行效果无水印,提供Matlab2022a版本代码,含详细中文注释和操作视频。适用于金融市场、气象预报等领域,有效处理非线性数据,提高预测稳定性和效率。
|
5天前
|
机器学习/深度学习 算法 索引
单目标问题的烟花优化算法求解matlab仿真,对比PSO和GA
本项目使用FW烟花优化算法求解单目标问题,并在MATLAB2022A中实现仿真,对比PSO和GA的性能。核心代码展示了适应度计算、火花生成及位置约束等关键步骤。最终通过收敛曲线对比三种算法的优化效果。烟花优化算法模拟烟花爆炸过程,探索搜索空间,寻找全局最优解,适用于复杂非线性问题。PSO和GA则分别适合快速收敛和大解空间的问题。参数调整和算法特性分析显示了各自的优势与局限。
|
27天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
13天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。
|
20天前
|
存储 算法
基于HMM隐马尔可夫模型的金融数据预测算法matlab仿真
本项目基于HMM模型实现金融数据预测,包括模型训练与预测两部分。在MATLAB2022A上运行,通过计算状态转移和观测概率预测未来值,并绘制了预测值、真实值及预测误差的对比图。HMM模型适用于金融市场的时间序列分析,能够有效捕捉隐藏状态及其转换规律,为金融预测提供有力工具。