c++中的方法

news2025/2/23 6:17:18

c++中的方法

static方法

与数据成员类似,方法有时会应用于全部对象而不是单个对象。可以编写static方法和数据成员。在方法声明前加上static即可。对于方法的定义前则不需要重复使用static关键字。

class Foo
{
public:
    static int sumFunc(int a, int b);
};

int Foo::sumFunc(int a, int b)
{
    cout << format("a + b = {}", a + b) << endl;
    return a + b;
}

需要注意的是static方法不属于某个特定的对象,因此没有this指针。当用某个特定对象调用static方法时,static方法不会访问这个对象的非static数据成员。实际上,static方法就像普通函数一样,唯一不同之处在于它可以访问类的private和protected的static成员。如果同一个类型的其他对象对于static方法可见(例如传递了对象的指针,或者引用作为参数),那么static方法也可以访问其他对象的private和protected的非static数据成员。

如果想要在类的外面调用静态方法,需要用类名+作用域解析运算符来限定方法的名称,静态方法的访问控制和普通方法一样。

const方法

const对象的值不可以改变。如果使用const对象、const对象的引用和指向const对象的指针,编译器将不允许调用对象的任何方法,除非这些方法保证不改变任何数据成员。为了保证方法不改变数据成员,可以使用const关键字标记方法本身。

class Foo
{
public:
    Foo(int a, int b) : m_proa(a), m_pria(a) {}
    static int sumFunc(int a, int b, Foo &foo);
    
    void print(Foo &foo) const;
protected:
    int m_proa;
    static int m_prob;

private:
    int m_pria;
    static int m_prib;
};
int Foo::m_prob(10);
int Foo::m_prib(11);

// const说明符是方法原型的一部分,必须放在方法的定义中!
void Foo::print(Foo &foo) const
{
    m_pria = 10; // 错误,不可以修改成员变量
    cout << "foo.pria = " << foo.m_pria << endl;
}

将方法标记为const,就是与客户代码订下了约定,承诺不会在方法内改变对象内部的值。const的工作原理是将方法内用到的数据成员都标记为const引用,因此如果试图修改数据成员,编译器会报错。

不能将static方法声明为const,编译器会报错,因为这样是多余的。静态方法没有类的事例,因此不可能改变内部的值。

非const对象可以调用const方法和非const方法。然而,const对象只能调用const方法。

在这里插入图片描述

所以应该养成良好的编程习惯,将不修改对象的所有方法声明为const,这样就可以在程序中使用const对象的引用。注意const对象也会被销毁,它们的析构函数也会被调用,因此不应该将析构函数标记为const。

mutable数据成员

有时候编写的方法在逻辑上是const方法,但是碰巧改变了对象的数据成员。这个改动对于用户可见的数据没有任何影响,但是严格来说的确做了改变,因此编译器不允许将这个方法声明为const。

例如我们想统计一个函数的执行次数,很简单,只需要加入一个计数器来计算调用次数即可。但是因为要改变这个计数器的值,所以不能将该方法设置为const。解决办法就是将计数器这个变量设置为mutable,告诉编译器const()方法中允许修改这个值。示例如下:

class Foo
{
public:
    Foo(int a, int b) : m_proa(a), m_pria(a) {}
    static int sumFunc(int a, int b);
    int sum3Func(int a, int b, int c);

    void print(Foo &foo) const;

protected:
    int m_proa;
    static int m_prob;

private:
    int m_pria;
    mutable int count{0};
    static int m_prib;
};
int Foo::m_prob(10);
int Foo::m_prib(11);

void Foo::print(Foo &foo) const
{
    ++count;
    cout << "foo.pria = " << foo.m_pria << endl;
}

方法重载

函数名称相同,参数的个数或类型不同,这样的方法就是重载,例如最简单的无参构造函数与有参构造函数,函数的参数个数不同,名字相同所以构成了重载。c++不允许仅根据方法的返回类型重载方法名称,因为在大多数情况下不能判断调用哪个方法实例。例如,如果任何地方都没有使用方法的返回值,编译器将无法判断要使用哪个方法的实例。

可以通过生成 -o文件,然后在使用nm命令查看!示例:

class Foo
{
public:
    int add(int a, int b);
    double add(double a, double b);
    int add(int a, int b, int c);
};

int Foo::add(int a, int b)
{
    return a + b;
}

double Foo::add(double a, double b)
{
    return a + b;
}

int Foo::add(int a, int b, int c)
{
    return a + b + c;
}

int main()
{
    Foo foo;
    int a{1}, b{2}, c{3};
    double d{5}, e{6};
    cout << "add = " << foo.add(a, b) << endl;
    cout << "add = " << foo.add(d, e) << endl;
    cout << "add = " << foo.add(a, b, c) << endl;
}

执行操作

g++ test.cc -c
nm test.o

输出关键结果:

0000000000000018 T _ZN3Foo3addEdd
0000000000000000 T _ZN3Foo3addEii
0000000000000040 T _ZN3Foo3addEiii

可以看到addE后面一个有两个’d’,一个有两个’i’、一个是有三个’i’。基本上可以看出重载的规则是根据参数的个数、类型有关,与返回类型无关。

基于const的重载

还要注意的是,可以根据const重载方法。也就是说,可以编写两个名称相同、参数也相同的方法,其中一个是const,另外一个不是。如果是const对象,就调用const方法;如果是非const对象,就调用非const方法。

示例:

class Foo
{
public:
    int add(int a, int b);
    int add(int a, int b) const;
};

通常情况下const版本与非const版本的实现是一样的。为避免代码重复,可以使用std::as_const()在非const方法内直接调用重载的const方法。ps:c++17引入的as_const()定义在< utility>中,功能是将左值转成const类型。

int Foo::add(int a, int b) const
{
    cout << "add(i, i)" << endl;
    return a + b;
}

int Foo::add(int a, int b)
{
    return as_const(*this).add(a, b);
}

显示删除重载

重载方法可以显示被删除,可以用这种方法禁止调用具有特定参数的数据成员函数。例如:

cout << foo.add(12.0, 34.0) << endl;
cout << foo.add(12, 34) << endl;

第二行,编译器会调用add(double, double)的重载方法,由于某些原因,你不想以整型的方式调用add,那么可以显示删除add的整型重载版本。

int add(int a, int b) const = delete;

通过这一改动,以整型为参数调用,编译器就会提示报错。

引用限定方法

可以对类的非临时和临时实例调用普通类方法,假设有以下类:

class TextHolder {
public:
    TextHolder(string text) : m_text { move(text) } {}
    const string& getText() const { return m_text; };
private:
    string m_text;
};

毫无疑问,可以在TextHolder的非临时实例上调用getText()方法,例如:

TextHolder textHolder {"hello world"};
cout << textHolder.getText() << endl;

然而,getText()也可以被临时实例调用

cout << TextHolder{ "hello world" }.getText() << endl;
cout << move(textHolder).getText() << endl;

可以显示指定能够调用某个方法的实例类型,无论是临时实例还是非临时实例。这是通过向方法添加一个所谓的引用限定符来实现的。如果只应用在非临时实例上调用方法,则在方法头之后添加一个&限定符。类似地,如果只应用在临时实例上调用方法,则要添加一个&&限定符。

下面修改的textHolder类通过将返回m_text的const引用来实现&限定的getText()。另一方面,&&限定的getText()返回m_text的右值引用,以便可以将m_text移出TextHolder。例如,如果你希望从临时TextHolder实例检索文本,则这可能更有效。

class TextHolder
{
public:
    TextHolder(string text) : m_text{move(text)} {}
    const string &getText() const &
    {
        cout << "const string &getText() const &" << endl;
        return m_text;
    }
    string &&getText() &&
    {
        cout << "string &&getText() &&" << endl;
        return move(m_text);
    }

private:
    string m_text;
};

调用:

TextHolder textHolder{"hello world"};
cout << textHolder.getText() << endl
     << endl;

cout << TextHolder{"hello world"}.getText() << endl;
cout << move(textHolder).getText() << endl;

执行结果:

const string &getText() const &
hello world

string &&getText() &&
hello world
string &&getText() &&
hello world

内联方法

c++提供了这样一种能力:可以建议函数或者方法的调用不在生成的代码中实现,就像调用独立的代码块那样。相反,编译器应将方法体直接插入调用方法的位置(编译阶段)。这个过程称为内联(inline),具有这一行为的方法称为内联方法。

可以在方法或函数定义的名称之前使用inline关键字,将某个方法或者函数指定为内联的。例如:

inline void print();

这提示编译器,用实际的方法体替换对print()的调用,而不是生成代码进行函数调用,注意:inline关键字只是提示编译器。如果编译器认为这会降低性能,就会忽略该关键字。

需要注意,在所有调用了内联函数或内联方法源文件中,内联方法或内联函数的定义必须有效。考虑这个问题,如果没有看到函数的定义,编译器如何替换函数体?因此,如果编写了内联方法,应该将方法定义在与其所在的类的定义放在同一文件中。

高级c++编译器不要求将内联方法的定义与类的定义放在同一个文件中。例如,Microsoft Visual C++支持链接时代码生成(Link-Time Code Generation,LTCG),会自动将较小的函数内联,哪怕这些函数没有声明为内联的或者没有在头文件中定义,也同样如此。GCC和Clang具有类似的功能。

在c++20模块之外,如果方法的定义直接放在类定义中,则该方法会隐式标记为inline,即使不使用inline关键字。对于c++20中模块导出的类,情况不再如此。如果希望这些方法是内联的,则需要使用inline关键字标记它们。

默认参数

C++中,默认参数与方法重载类似。在原型中可为函数或者方法的参数指定默认值,如果用户指定了这些参数,默认值就会失效。如果用户忽略了这些参数,将会使用默认值。但是存在一个限制,只能从最右边的参数开始提供连续的默认参数列表,否则编译器无法用默认参数匹配缺失的参数。默认参数可用于函数、方法和构造函数。示例:

class Spreadsheet
{
public:
    Spreadsheet(size_t width = 100, size_t height = 200){};
};

int main()
{
    Spreadsheet s1;
    Spreadsheet s2{7};
    Spreadsheet s3{8, 10};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/550121.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

康耐视Visionpro工具-CogPMAlignTool为什么是最牛工具?

1.算法:有六种选项,分别是:PatMax,PatQuick, PatMax 与 PatQuick, PatFlex,PatMax-高灵敏度,透视 Patmax。 PatQuick 特点:速度最快,对于三维或者低质量原件最佳,承受更多图像差异; PatMax 特点:精确度最高,在二维元件上表现佳,最适合于细微细节; PatFlex 特点…

4. 通讯录实现的需求分析和架构设计

本文实现的是通讯录产品的需求分析和架构设计&#xff0c;重点在于结构层次的设计&#xff0c;方便代码阅读和维护。 一、通讯录实现的需求分析 1、通讯录的功能清单 添加一个人员打印显示所有人员删除一个人员查找一个人员保存文件加载文件 2&#xff0c;数据存储信息 人员…

[CTF/网络安全] 攻防世界 disabled_button 解题详析

[CTF/网络安全] 攻防世界 disabled_button 解题详析 input标签姿势disable属性总结 题目描述&#xff1a;X老师今天上课讲了前端知识&#xff0c;然后给了大家一个不能按的按钮&#xff0c;小宁惊奇地发现这个按钮按不下去&#xff0c;到底怎么才能按下去呢&#xff1f; input标…

Tiny+ 语言词法之C语言

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 语义分析本质上就是在语法分析的基础上进一步完善分析的功能。举个例子来说&#xff0c;在语法分析部分的 if_stmt 函数中&#xff0c;在语义上判断条件必须返回布尔类型的值&#xff0c;因此我们加入一个判断&#xff0c;判断…

Unity之OpenXR+XR Interaction Toolkit示例Demo详解

一.前言 自从升级Unity版本到2021,然后使用OpenXR开发VR之后,我们整个团队的开发效率都提升了不少,这证明了不管什么领域,统一接口,统一规范都是必须的。 关于XR Interaction Toolkit插件,我已经写了几篇文章了,今天才想起来,最基础的Demo讲解还没有写,其实官方的这个…

chatgpt赋能Python-pythonfor循环5次

Python中for循环的使用方法及技巧 Python作为一种高级编程语言&#xff0c;其独特的语法结构和方便的操作方法受到了越来越多人的欢迎和喜爱。其中&#xff0c;for循环是Python程序员必备的基本技巧之一。在这篇文章中&#xff0c;我们将介绍Python中for循环的使用方法及技巧。…

HTTP协议【面试高频考点】

目录 一、HTTP 响应 1.首行 2.状态码&#xff08;经典面试题&#xff0c;必考&#xff09; 2.1 200 OK 2.2 404 Not Found 2.3 403 Forbidden 2.4 500 Internal Server Error 2.5 504 Gateway Timeout 2.6 302 Move temporarily 2.7 301 Moved Permanently 2.8 状态…

clearmymac4.13.5专业的Mac系统清理优化工具

CleanMyMac X是一款功能强大的Mac清理工具&#xff0c;它可以扫描您的Mac电脑&#xff0c;清除垃圾文件&#xff0c;卸载无用的应用程序&#xff0c;并优化系统性能。此外&#xff0c;CleanMyMac X还可以找到和修复Mac电脑上的许多其他问题&#xff0c;即使您不是技术专家也可以…

chatgpt赋能Python-pythona__a

Python中的aa 介绍 Python是一种流行的编程语言&#xff0c;具有简单易学和可读性强的特点。在Python中&#xff0c;常常使用aa这样的表达式&#xff0c;它表示将变量a的原始值加上它自己的值&#xff0c;然后将结果赋值给变量a。这种语法看起来很简单&#xff0c;但实际上有…

C语言函数大全-- _w 开头的函数(5)

C语言函数大全 本篇介绍C语言函数大全-- _w 开头的函数 1. _wspawnl 1.1 函数说明 函数声明函数功能int _wspawnl(int mode, const wchar_t* cmdname, const wchar_t* arglist, ...);启动一个新的进程并运行指定的可执行文件 参数&#xff1a; mode &#xff1a; 启动命令的…

【008】C++数据类型之重要关键字详解

C数据类型之重要关键字详解 引言一、const修饰普通变量重点说明 二、register修饰寄存器变量三、volatile强制访问内存四、sizeof测试类型的大小五、typedef关键字总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计和开发&#xff0c;理论与代码实践结合&a…

搭建go web 框架

思想base部分day1:封装gee封装context上下文封装前缀tree路由树分组封装group与中间件封装文件解析封装封装错误处理测试 思想 web框架服务主要围绕着请求与响应来展开的 搭建一个web框架的核心思想 1 便捷添加响应路径与响应函数(base) 2 能够接收多种数据类型传入(上下文cont…

第二章 表操作

一、数据表的设计理念 数据表是包括数据库所有数据的数据库对象&#xff0c;数据在表中的组织方式与在电子表格中相似&#xff0c;都是按行和列的格式组织的&#xff0c;其中每一行代表一条唯一的记录&#xff0c;每一列代表记录中的字段&#xff0c;表中的数据库对象包含列、…

Godot4节点树右键菜单添加自定义选项

前言 查看godot的源码推荐使用在线版vscode直接从github上看。&#xff08;直接把网址的com改成dev即可&#xff09; 重点查看以下源码 scene_tree_dock.h scene_tree_dock.cpp 开始 tool extends EditorPluginvar window var scene_menustatic func find_child_by_class(no…

OneDrive同步角标消失 - 解决方案

问题 在电脑端使用OneDrive时&#xff0c;文件管理器OneDrive文件夹内的文件会在左下角显示同步状态&#xff0c;如下图。若没有显示同步角标&#xff0c;则此功能出现异常&#xff0c;下文介绍如何显示同步角标。 值得一提的是&#xff0c;同步角标只起到显示作用&#xff0…

secure CRT 颜色主题 系统间拷贝

文章目录 颜色主题如何切换 SecureCRT 颜色主题如何新建SecureCRT 颜色 主题如何拷贝我的颜色主题,主题名为pic VIM系统间拷贝vim中 ubuntu 拷贝 到 win1. 确保 ubuntu 上的 vim 支持 clipboard 特性2. 在 ~/.vim/vimrc 中添加设置3. vim中 win拷贝到ubuntu SecureCRT 关键字高…

STM32实现基于RS485的简单的Modbus协议

背景 我这里用STM32实现&#xff0c;其实可以搬移到其他MCU&#xff0c;之前有项目使用STM32实现Modbus协议 这个场景比较正常&#xff0c;很多时候都能碰到 这里主要是Modbus和变频器通信 最常见的是使用Modbus实现传感器数据的采集&#xff0c;我记得之前用过一些传感器都…

pg事务:隔离级别历史与SSI

事务隔离级别的历史 ANSI SQL-92定义的隔离级别和异常现象确实对数据库行业影响深远&#xff0c;甚至30年后的今天&#xff0c;绝大部分工程师对事务隔离级别的概念还停留在此&#xff0c;甚至很多真实的数据库隔离级别实现也停留在此。但后ANSI92时代对事物隔离有许多讨论甚至…

队列的实现(附含两道经典例题)

&#x1f349;文章主页&#xff1a;阿博历练记 &#x1f4d6;文章专栏&#xff1a;数据结构与算法 &#x1f68d;代码仓库&#xff1a;阿博编程日记 &#x1f365;欢迎关注&#xff1a;欢迎友友们点赞收藏关注哦&#x1f339; 文章目录 &#x1f33e;前言&#x1f3ac;队列&…

探索Windows CMD命令的经典应用:实用技巧大揭秘,值得收藏

文章目录 导语&#xff1a;第一部分&#xff1a;CMD命令基础1. ipconfig&#xff1a;获取网络配置信息2. ping&#xff1a;测试网络连接3. dir&#xff1a;查看目录内容4. telnet&#xff1a;远程登录和测试网络服务 第二部分&#xff1a;进程管理5. tasklist&#xff1a;查看正…