当前位置:首页 > 技术 > 正文内容

C++中const关键字深度解析

访客 技术 2026年7月12日 1

概述

const在C++中是一个重要的修饰符,它主要用于向编译器表明某些值或对象不应该被修改。虽然const不能完全阻止代码修改数据(通过强制类型转换可以绕过),但它为代码提供了清晰的语义声明,帮助开发者表达设计意图。

在C++编程中养成正确使用const的习惯非常重要,它可以让代码更安全、更易读,同时也能帮助编译器进行更好的优化。

const的基本用法

1. 基础常量声明

const int MAX_SIZE = 100; // 声明一个不可修改的整型常量

一旦const变量被初始化,就不能再对其赋值。编译器会确保这一约束得到执行。

2. 指针与const的组合

const与指针结合时,位置不同会产生不同的效果。

情况一:const在星号前面

int value = 10;
const int* ptr1 = &value;  // 指向整型常量的指针
// *ptr1 = 20;  // 错误:不能通过指针修改值
ptr1 = nullptr;  // 正确:可以改变指针本身的值

这种写法表示指针指向的内容是常量,不能通过该指针修改目标对象,但指针本身可以指向其他地址。等价写法:int const* ptr1 = &value;

情况二:const在星号后面

int value = 10;
int* const ptr2 = &value;  // 指向整型的常量指针
*ptr2 = 20;  // 正确:可以修改指针指向的内容
// ptr2 = nullptr;  // 错误:不能改变指针本身的指向

这种写法表示指针本身是常量,不能改变指针的指向,但可以通过该指针修改目标对象的内容。

情况三:前后都有const

int value = 10;
const int* const ptr3 = &value;  // 指向整型常量的常量指针
// *ptr3 = 20;  // 错误:不能修改内容
// ptr3 = nullptr;  // 错误:不能改变指向

这种写法同时锁定了指针本身和指针指向的内容,两者都不能修改。

const在成员函数中的应用

在类中,const可以放在成员函数声明的末尾,这种用法称为常量成员函数。

class Player
{
private:
    int m_Score;
    int* m_Ptr;

public:
    int GetScore() const  // 常量成员函数
    {
        // m_Score = 100;  // 错误:不能修改成员变量
        return m_Score;
    }

    const int* GetPointer() const
    {
        return m_Ptr;
    }

    void SetScore(int score)
    {
        m_Score = score;  // 可以修改,因为非常量成员函数
    }
};

常量成员函数承诺不会修改类的任何成员变量(除非该成员被声明为mutable)。这对于使用const对象或const引用调用成员函数时非常重要。

当一个对象被声明为const时,只有const成员函数可以被调用:

void DisplayInfo(const Player& player)
{
    // player.SetScore(10);  // 错误:SetScore是非常量函数
    std::cout << player.GetScore() << std::endl;  // 正确:GetScore是const函数
}

mutable关键字

有时需要在常量成员函数中修改某个成员变量,这时可以使用mutable修饰符。

class Logger
{
private:
    std::string m_Name;
    mutable int m_AccessCount;  // 可变成员变量

public:
    Logger(const std::string& name) : m_Name(name), m_AccessCount(0) {}

    const std::string& GetName() const
    {
        m_AccessCount++;  // 正确:mutable变量可以在const函数中修改
        return m_Name;
    }

    int GetAccessCount() const
    {
        return m_AccessCount;
    }
};

mutable关键字允许在常量成员函数中修改特定的数据成员,这在实现缓存、计数器等场景中非常有用。

参数传递中的const使用

使用const修饰函数参数可以提高代码的安全性和清晰度:

// 按值传递:const无实际意义
void Function1(int value);

// 按指针传递:防止指针指向的内容被修改
void Function2(const int* ptr);

// 按指针传递:防止指针本身被修改
void Function3(int* const ptr);

// 按引用传递:防止引用对象被修改(推荐)
void Function4(const int& ref);

完整示例代码

#include <iostream>
#include <string>

class Player
{
private:
    std::string m_Name;
    int m_Level;
    int* m_Data;
    mutable int m_CallCount;

public:
    Player(const std::string& name, int level)
        : m_Name(name), m_Level(level), m_Data(nullptr), m_CallCount(0) {}

    // 常量成员函数
    const std::string& GetName() const
    {
        m_CallCount++;  // mutable允许修改
        return m_Name;
    }

    int GetLevel() const
    {
        return m_Level;
    }

    // 返回常量指针的常量指针
    const int* const GetData() const
    {
        return m_Data;
    }

    void SetLevel(int level)
    {
        m_Level = level;
    }
};

void PrintPlayer(const Player& p)
{
    std::cout << "Name: " << p.GetName() << std::endl;
    std::cout << "Level: " << p.GetLevel() << std::endl;
}

int main()
{
    const int MAX_LEVEL = 99;
    int current = 50;

    // 情况1:指向常量的指针
    const int* ptr1 = &current;
    // *ptr1 = 100;  // 错误
    ptr1 = &MAX_LEVEL;  // 正确

    // 情况2:常量指针
    int* const ptr2 = &current;
    *ptr2 = 100;  // 正确
    // ptr2 = &MAX_LEVEL;  // 错误

    // 情况3:指向常量的常量指针
    const int* const ptr3 = &MAX_LEVEL;
    // 两者都不能修改

    Player hero("Hero", 1);
    PrintPlayer(hero);

    hero.SetLevel(10);
    PrintPlayer(hero);

    return 0;
}

总结

  • const用于声明不可变的内容,是代码设计的重要工具
  • const在*前:保护指针指向的内容不被修改
  • const在*后:保护指针本身不被修改
  • const成员函数:承诺不修改对象状态
  • mutable:允许在const函数中修改特定成员

合理使用const可以让代码意图更清晰,同时帮助编译器发现潜在的错误。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。