【C++】const对象和const成员

简介: 如果我们在定义一个对象之后,不希望在后面对这个对象进行修改,那么我们可以把这个对象声明为const对象。 声明为const对象之后,这个对象的所有数据成员后面都不能被修改! const对象定义类对象时可以将其指定为const对象。

如果我们在定义一个对象之后,不希望在后面对这个对象进行修改,那么我们可以把这个对象声明为const对象。
声明为const对象之后,这个对象的所有数据成员后面都不能被修改!

const对象

定义类对象时可以将其指定为const对象。定义后const对象不能再被修改。
const对象不能调用非const类型的成员函数。
有两种方法来定义一个const对象:
const 类名 对象名
类名 const 对象名
这两种方法是等价的。

如果一个对象被定义成const对象,那么它就不能调用这个类中的非const成员函数。
const对象调用的成员函数一定都得是const!

//const
const CTime time4(10);
CTime const time5;

如果你用const对象引用了这个类中的非const成员函数,就会报错:

错误  1   error C2662: “int CTime::getHour(void)”: 不能将“this”指针从“const CTime”转换为“CTime &”
e:\chenhaoxiang\20170603\test2\test2\mian.cpp   34  1   test2

其实就是告诉我们const对象不能引用非const成员函数
为什么要有这个规则:
因为在非const成员函数内部可能对对象进行修改,比如set函数
这个规则也就是强制用户不要对const成员进行错误的修改

const成员

1.const数据成员

也就是变量,比如实例中的m_hour,m_minute是普通数据成员

在类内部使用const关键字来声明const数据成员。const数据成员的值不能被修改。
初始化时比较特殊,只能通过初始化列表初始化。不能在构造函数里赋值。

2.初始化列表

初始化列表:
除了在构造函数中对数据成员进行初始化,C++还提供另外一种方法来对数据成员进行初始化
初始化列表并不是在构造函数内进行初始化
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。

const int num;

必须初始化,而且不能在构造函数中初始化!

CTime::CTime() : num(10){

    m_hour = 0;
    m_minute = 0;
    m_second = 0;
    m_nNum++;
    cout << m_nNum << endl;
}
CTime::CTime(int hour) : num(10){
    this->m_hour = hour;
    //(*this).m_hour = hour; //效果一样的
}

//复制构造函数
CTime::CTime(CTime& time) : num(10){
    m_hour = time.m_hour;
    m_minute = time.m_minute;
    m_second = time.m_second;
    //cout << "进入复制构造函数" << endl;
}

每一个构造函数都需要初始化这个const成员,而且复制构造函数也需要初始化num,因为复制构造函数也是一种构造函数!

3.const成员函数

const成员函数只能被const对象引用。const成员函数内可以引用const数据成员,也可以引用非const数据成员,但不能修改非const数据成员的值。但不能调用非const成员函数。

int getNum() const;

对于const函数的外部定义,也需要写const限定符

int CTime::getNum() const {
    return num;
}

const成员函数存在的意义在于它能被const常对象调用

CTime const time5;
    cout << time5.getNum() <<endl;

如果在const成员函数的定义中出现了任何修改对象成员数据的现象,都会在编译时被检查出来

如果我们是真的想在const成员函数中修改值呢,比如我需要m_age++;
比如下面定义了一个m_age 类成员:

int m_age;
int CTime::getNum() const {
    if (m_age == 0){
        m_age++;
    }
    else{
        m_age = 0;
    }
    return num;
}

假如我们不做其他事情,这样的写法,在编译时是无法通过的。

有些时候,我们想要让const函数具有修改某个成员数据值的能力。
比如一些内部的状态量,对外部用户无所谓,但是对整个对象的运行却大有用处,如支持缓存的技术。
遇到这种问题,我们可以把一个成员数据定义为mutable(多变的),它表示这个成员变量可以被const成员函数修改却不违法。
比如下面定义了这样一个m_age 类成员:

mutable int m_age;
int CTime::getNum() const {
    if (m_age == 0){
        m_age++;
    }
    else{
        m_age = 0;
    }
    return num;
}

这样,即使像getNum()这样的const成员函数修改它也是合法的。
但需要注意的时,不要滥用mutabe描述符,如果在某个类中只有少数一部分是被允许const常量函数修改的,使用mutable是再合适不过的。如果大部分数据都定义为mutable,那么最好将这些需要修改的数据放入另一个独立的对象里,并间接地访问它。

源代码下载地址:

GITHUB源码下载地址: 点我进行下载

本文章由[谙忆]编写, 所有权利保留。
欢迎转载,分享是进步的源泉。

转载请注明出处:http://chenhaoxiang.cn

本文源自人生之旅_谙忆的博客

目录
相关文章
|
12月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
12月前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
11月前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
11月前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。
|
11月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
613 6
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
283 19
|
11月前
|
编译器 C++
类和对象(下)C++
本内容主要讲解C++中的初始化列表、类型转换、静态成员、友元、内部类、匿名对象及对象拷贝时的编译器优化。初始化列表用于成员变量定义初始化,尤其对引用、const及无默认构造函数的类类型变量至关重要。类型转换中,`explicit`可禁用隐式转换。静态成员属类而非对象,受访问限定符约束。内部类是独立类,可增强封装性。匿名对象生命周期短,常用于临时场景。编译器会优化对象拷贝以提高效率。最后,鼓励大家通过重复练习提升技能!
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
478 13
|
12月前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
12月前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。