C++基础(七):类和对象(中-2)

news2025/3/9 10:32:01

      上一篇博客学的默认成员函数是类和对象的最重要的内容,相信大家已经掌握了吧,这一篇博客接着继续剩下的内容,加油!

目录

一、const成员(理解)

1.0 引入

1.1 概念

1.2  总结

1.2.1 对象调用成员函数

1.2.2 成员函数调用成员函数

二、取地址及const取地址操作符重载(了解)

三、日期类的重新规范书写

3.1 Date.h

3.2 Date.cpp


一、const成员(理解)

1.0 引入

      先看代码:

#include <iostream>
using namespace std;
class Date
{
public:
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }


    void Print()
    {
        cout << "year:" << _year << endl;
        cout << "month:" << _month << endl;
        cout << "day:" << _day << endl << endl;
    }

private:
    int _year;     // 年
    int _month;   // 月
    int _day;     // 日
};


void func( Date d)    这里的形参为对象,它会进行调用一次拷贝构造
{
    d.Print();
}


int main()
{
    Date d1(2024, 7, 20);
    func(d1);             这里直接传递的是对象

    return 0;
}

程序运行结果:、

 

再看代码: 

#include <iostream>
using namespace std;
class Date
{
public:
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }


    void Print()
    {
        cout << "year:" << _year << endl;
        cout << "month:" << _month << endl;
        cout << "day:" << _day << endl << endl;
    }

private:
    int _year;     // 年
    int _month;   // 月
    int _day;     // 日
};


void func( const Date& d)  这里的形参为对象的引用/别名,它就是d1的别名,同一个实体,不会进行拷贝构造                     加const代表我引用这个对象,但是我不会通过引用从而修改这个对象!
{
    d.Print();
}


int main()
{
    Date d1(2024, 7, 20);
    func(d1);             这里直接传递的是对象

    return 0;
}

程序运行结果:

为什么会是上面的结果???

其实,这就是我们在入门阶段学习的指针的相互赋值,指针的能力不能出现扩张,这样编译器会报错!那又该如何解决呢?  这便引入了要学习的const成员。

  void Print()   const    //  void Print(const Date* this )   
    {
        cout << "year:" << _year << endl;
        cout << "month:" << _month << endl;
        cout << "day:" << _day << endl << endl;
    }

1.1 概念

       将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数 隐含的this指针,表明在该成员函数中不能对类的任何成员变量进行修改。(const修饰的指针)比如:_year= 2026; (编译器底层:this->_year=2026;) 这是不允许的!

复习:

  1. const  Date* p1 :  const修饰的是指针指向的对象,也就是说不可以通过这个指针来修改对象的数据!
  2. Date  const * p2 : 和上面的一样,const修饰的是指针指向的对象,也就是说不可以通过这个指针来修改对象的数据!
  3. Date   * const p3 : const修饰的是指针p3本身,也就是说,不可以修改指针的指向!
  4. const  Date* const  p4: const既修饰指针指向的对象,也就是说不可以通过这个指针来修改对象的数据!也修饰了指针p3本身,也就是说,不可以修改指针的指向!(双重限定)

1.2  总结

1.2.1 对象调用成员函数

1. const对象可以调用非const成员函数吗?

      不可以。const对象只能调用const成员函数,因为const对象不能被修改,而非const成员函数可能会修改对象的状态。

class MyClass 
{
   public:
       void nonConstFunc() 
       {
           // 修改对象状态的代码
       }

      void constFunc() const 
      {
        // 不修改对象状态的代码
      }
};

int main()
 {
      const MyClass obj;
      obj.constFunc();     // 可以调用
      obj.nonConstFunc();  // 编译错误
      return 0;
 }

2. 非const对象可以调用const成员函数吗?

       可以。const对象可以调用const成员函数,因为const成员函数保证不会修改对象的状态。

class MyClass 
{
public:
    void nonConstFunc() 
    {
        // 修改对象状态的代码
    }
    void constFunc() const 
   {
        // 不修改对象状态的代码
    }
};

int main() 
{
    MyClass obj;
    obj.constFunc();     // 可以调用
    obj.nonConstFunc();  // 也可以调用
    return 0;
}

1.2.2 成员函数调用成员函数

1. const成员函数内可以调用其它的非const成员函数吗?

       不可以。const成员函数不能调用非const成员函数,因为这会违反const成员函数不修改对象状态的承诺。

class MyClass
{
public:
    void nonConstFunc() 
    {
        // 修改对象状态的代码
    }
    void constFunc() const 
    {
        nonConstFunc();  // 编译错误
    }
};

int main() 
{
    MyClass obj;
    obj.constFunc();
    return 0;
}

2. 非const成员函数内可以调用其它的const成员函数吗?

      可以。const成员函数可以调用const成员函数,因为const成员函数不会修改对象的状态。

class MyClass 
{
public:
    void nonConstFunc() 
    {
        constFunc();  // 可以调用
        // 修改对象状态的代码
    }
    void constFunc() const
   {
        // 不修改对象状态的代码
   }
};

int main() 
{
    MyClass obj;
    obj.nonConstFunc();
    return 0;
}

理解记忆,明确一个原则:只要调用成员函数都涉及this指针,我们就要分析指针类型的变化。

 

结论:什么时候会给成员函数加const?

         只要成员函数中不需要修改成员变量最好都加上const,但是,如果你需要改变成员变量,你就不能加const!因为这个时候const对象可以调用这个const修饰的成员函数,非const对象(普通对象)也可以调用这个const修饰的成员函数。

二、取地址及const取地址操作符重载(了解)

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

#include <iostream>
using namespace std;
class Date
{
public:
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }


    void Print()  const
    {
        cout << "year:" << _year << endl;
        cout << "month:" << _month << endl;
        cout << "day:" << _day << endl << endl;
    }

    /*自己实现的取地址运算符重载函数以及const取地址操作符重载函数,构成函数重载
    Date* operator&()
    {
        return this;
        //return nullptr;
        
    }

    const Date* operator&() const
    {
        cout<< "operator&()"<<endl;
        return this;
        //return nullptr;
    }
    */


private:
    int _year;     // 年
    int _month;   // 月
    int _day;     // 日
};


void func( const Date& d)
{
    d.Print();
}


int main()
{
    Date d1(2024, 7, 20);
    Date d2(2024, 7, 21);
    const Date d3(2024, 7, 22);

    cout << &d1 << endl; //调用的是取地址运算符重载函数,不实现的话,编译器默认会生成
    cout << &d2 << endl; //调用的是取地址运算符重载函数,不实现的话,编译器默认会生成

    cout << &d3 << endl;  //调用的是const取地址操作符重载函数,不实现的话,编译器默认会生成

    return 0;
}

         这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如不想让别人获取到指定的内容!

三、日期类的重新规范书写

3.1 Date.h

#pragma once
#include <iostream>
using namespace std;

class Date
{
public:

    int GetMonthDay(int year, int month)  const;
    Date(int year = 0, int month = 1, int day = 1);
    Date(const Date& d);
    ~Date();
    void  Print() const;

    /*运算符重载*/
    bool  operator<(const Date& d)   const;
    bool  operator==(const Date& d)  const;
    bool  operator<=(const Date& d)  const;
    bool  operator>(const Date& d)   const;
    bool  operator>=(const Date& d)  const;
    bool  operator!=(const Date& d)  const;
    Date& operator=(const Date& d);

    Date  operator+(int day)         const;
    Date& operator+=(int day);       //不能加
    Date  operator-(int day)         const;
    Date& operator-=(int day);       //不能加
    Date& operator++();             //不能加
    Date  operator++(int);
    Date& operator--();
    Date  operator--(int);
    int   operator-(const Date& d) const;

private:
    int _year;
    int _month;
    int _day;
};

3.2 Date.cpp

#define _CRT_SECURE_NO_WARNINGS 1

#include "Date.h"


int Date::GetMonthDay(int year, int month)    const  
{
    static int days[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int day = days[month];
    if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)))  
    {
        day += 1;
    }
    return day;
}


Date::Date(int year , int month , int day )   //缺省参数只在声明中给
{
    if (year >= 0 && month >= 1 && month <= 12 && day >= 1 && day <= GetMonthDay(year, month))
    {
        _year = year;
        _month = month;
        _day = day;
    }
    else
    {
        cout << "非法日期" << endl;
    }
}


Date::Date(const Date& d)
{
    _year = d._day;
    _month = d._month;
    _day = d._day;
}



Date::~Date()
{
    cout << "~Date()" << endl;
}



void Date::Print()  const
{
    cout << _year << "-" << _month << "-" << _day << endl;
}




bool Date::operator<(const Date& d)    const
{
    if (_year < d._year)
    {
        return true;
    }
    else if (_year == d._year && _month < d._month)
    {
        return true;
    }
    else if (_year == d._year && _month == d._month && _day < d._day)
    {
        return true;
    }

    return false;
}




bool   Date::operator==(const Date& d)  const
{
    if (_year == d._year && _month == d._month && _day == d._day)
    {
        return true;
    }
    return false;

}


bool   Date::operator<=(const Date& d)  const
{
    return *this < d || *this == d;           


}


bool   Date::operator>(const Date& d)  const
{
    return !(*this <= d);            

}

bool  Date::operator>=(const Date& d)   const
{
    return !(*this < d);           

}


bool   Date::operator!=(const Date& d)   const
{
    return !(*this == d);          

}



Date& Date::operator=(const Date& d)         
{
    if (this != &d)         
    {
        _year = d._day;
        _month = d._month;
        _day = d._day;
    }

    return *this;
}




Date Date::operator+(int day)  const
{
    Date ret(*this);     
    ret._day += day;
    while (ret._day > GetMonthDay(ret._year, ret._month))
    {
       
        ret._day -= GetMonthDay(ret._year, ret._month);
        ret._month++;

        if (ret._month == 13)   
        {
            ret._year++;
            ret._month = 1;     
        }
    }

    return ret;
}


Date& Date::operator+=(int day)
{
    if (day < 0)
    {
        return *this -= -day;
    }


    _day += day;
    while (_day > GetMonthDay(_year, _month))
    {
        
        _day -= GetMonthDay(_year, _month);
        ++_month;

        if (_month == 13)   
        {
            ++_year;
            _month = 1;     
        }
    }

    return *this;        
}



Date Date::operator-(int day) const
{
    Date ret(*this);     
    ret._day -= day;
    while (ret._day <= 0)   
    {
        --ret._month;
        if (ret._month == 0)
        {
            --ret._year;    
            ret._month = 12;   
        }

        ret._day += GetMonthDay(ret._year, ret._month);
    }
    return ret;
  
}


Date& Date::operator-=(int day)
{

    if (day < 0)
    {
        return *this += -day;  
    }


    _day -= day;
    while (_day <= 0)   
    {
        --_month;
        if (_month == 0)
        {
            --_year;    
            _month = 12;   
        }

        _day += GetMonthDay(_year, _month);

    }

    return *this;
}



Date& Date::operator++()
{
    *this += 1;
    return *this;     
}

Date Date::operator++(int)
{
    Date tmp(*this);  
    *this += 1;

    return tmp;  
}




Date& Date::operator--()
{
    *this -= 1;
    return *this;     
}



Date Date::operator--(int)
{
    Date tmp(*this);  
    *this -= 1;

    return tmp;   
}


int Date::operator-(const Date& d) const
{
    int flag = 1;

    Date max = *this;       
    Date min = d;

    if (*this < d)       
    {
        max = d;
        min = *this;
        flag = -1;
    }

    int n = 0;
    while (min != max)
    {
        ++min;
        ++n;
    }

    return n * flag;
}


        至此,C++面向对象-中全部内容就学习完毕,这一节内容比较重要,建议多看几遍,认真复习消化,熟练使用,C++相对来说较为复杂,我们应该时刻理清自己的思路,耐下心来,一点点积累, 星光不问赶路人,加油吧,感谢阅读,如果对此专栏感兴趣,点赞加关注! 

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

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

相关文章

人工智能系列-NumPy(二)

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 链接数组 anp.array([[1,2],[3,4]]) print(第一个数组&#xff1a;) print(a) print(\n) bnp.array([[5,6],[7,8]]) print(第二个数组&#xff1a;) print(b) print(\n) print…

web基础与HTTP协议(企业网站架构部署与优化)

补充&#xff1a;http服务首页文件在/var/www/html下的&#xff0c;一定是index.html命名的文件。才会显示出来。 如果该路径下没有相应的文件&#xff0c;会显示/usr/share/httpd/noindex下的index.html文件。 如果/usr/share/httpd/noindex没有index.html文件&#xff0c;会…

使用Llama3/Qwen2等开源大模型,部署团队私有化Code Copilot和使用教程

目前市面上有不少基于大模型的 Code Copilot 产品&#xff0c;部分产品对于个人开发者来说可免费使用&#xff0c;比如阿里的通义灵码、百度的文心快码等。这些免费的产品均通过 API 的方式提供服务&#xff0c;因此调用时均必须联网、同时需要把代码、提示词等内容作为 API 的…

2024年亚太中文赛数学建模竞赛B题 洪水灾害的数据分析与预测详细思路解析

2024年亚太中文赛数学建模竞赛B题 洪水灾害的数据分析与预测详细思路解析 解题方法&#xff1a; 首先就是对数据进行数据的预处理包括缺失值和异常值处理&#xff0c;之后就是分析哪些指标与洪水的发生有着密切的关联&#xff0c;可以使用相关性分析&#xff08;建议使用斯皮尔…

WMS,OMS,TMS三者之间是什么关系?

WMS、OMS 和 TMS 是供应链管理中的三个重要系统&#xff0c;它们分别管理仓库、订单和运输的不同方面。 三者的功能&#xff1a; 1、WMS (Warehouse Management System) - 仓库管理系统&#xff1a; 1):主要负责仓库内部的操作和管理&#xff0c;包括库存管理、仓储空间优化、…

4K Tokkit Pro for Mac:轻松管理TikTok的利器

在TikTok的海洋中畅游&#xff0c;你是否想有一个得力助手来帮你高效管理你的账号&#xff1f;4K Tokkit Pro for Mac正是你的不二之选&#xff01; 这款专为Mac用户打造的TikTok管理工具&#xff0c;拥有简洁的界面和强大的功能&#xff0c;让你轻松下载、管理和分享喜欢的Ti…

【算法笔记自学】入门篇(2)——算法初步

4.1排序 自己写的题解 #include <stdio.h> #include <stdlib.h>void selectSort(int A[], int n) {for(int i 0; i < n - 1; i) { // 修正索引范围int k i;for(int j i 1; j < n; j) { // 修正索引范围if(A[j] < A[k]) {k j;}}if (k ! i) { // 仅在…

[SAP ABAP] 版本管理

版本管理是指软件开发过程中各种程序代码、配置文件以及说明文档等文件变更的管理 生成版本 版本管理 对比版本 点击上述版本管理即可进行版本对比操作 补充扩展 我们可以使用事务码SE10对传输请求进行创建、修改、删除、合并以及更改所有者等操作 使用事务码SCC1进行不同cl…

微观特征轮廓尺寸测量:光学3D轮廓仪、共焦显微镜与台阶仪的应用

随着科技进步&#xff0c;显微测量仪器以满足日益增长的微观尺寸测量需求而不断发展进步。多种高精度测量仪器被用于微观尺寸的测量&#xff0c;其中包括光学3D表面轮廓仪&#xff08;白光干涉仪&#xff09;、共聚焦显微镜和台阶仪。有效评估材料表面的微观结构和形貌&#xf…

免费代理 IP 如何泄露您的个人信息?

互联网时代&#xff0c;信息安全和隐私保护成为人们关注的焦点。很多用户出于各种需要&#xff0c;使用代理服务器浏览网页或进行其他网络活动&#xff0c;其中免费代理IP因其免费的特点而受到广泛青睐。然而&#xff0c;免费代理IP并不总是一个安全可靠的选择&#xff0c;它们…

新架构下服务建模,关键在这6步!

随着AUTOSAR、SOA、以太网通讯等新技术、新理念的成熟化&#xff0c;面向软件、硬件、网络、电气等多领域的电子电气系统经历了多代架构方法论的迭代。如何跟随新技术和新理念的浪潮&#xff0c;构建起新型的汽车电子电气架构平台&#xff0c;以实现新老技术的快速更替和融合&a…

塑料颗粒烘干机相关制作技术

网盘 https://pan.baidu.com/s/1urgMadWbneDT-HNOZFwZOw?pwd5idr 再生塑料颗粒用烘干装置.pdf 塑料制品加工用颗粒烘干装置.pdf 塑料颗粒烘干机.pdf 塑料颗粒生产加工用循环烘干装置.pdf 塑料颗粒用高效率烘干装置.pdf 颗粒物料烘干机.pdf

windows启动Docker闪退Docker desktop stopped

Windows启动Docker闪退-Docker desktop stopped 电脑上很早就安装有Docker了&#xff0c;但是有一段时间都没有启动了&#xff0c;今天想启动启动不起来了&#xff0c;打开没几秒就闪退&#xff0c;记录一下解决方案。仅供参考 首先&#xff0c;参照其他解决方案&#xff0c;本…

Servlet与Servlet容器

什么是Servlet? Servlet是Java EE&#xff08;现称Jakarta EE&#xff09;中的一个组件&#xff0c;通常用于创建动态Web内容。Servlet是运行在Web服务器上的Java程序&#xff0c;它处理客户端的请求并生成响应。Servlet的核心功能是处理HTTP请求和响应。下面是一个servlet例…

imx6ull/linux应用编程学习(11)CAN应用编程基础

关于裸机的can通信&#xff0c;会在其他文章发&#xff0c;这里主要讲讲linux上的can通信。 与I2C,SPI等同步通讯方式不同&#xff0c;CAN通讯是异步通讯&#xff0c;也就是没有时钟信号线来保持信号接收同步&#xff0c;也就是所说的半双工&#xff0c;无法同时发送与接收&…

YARN运行流程源码分析

一、yarn任务执行流程图 在分析任务之前先走一下yarn内部的流程细节。 二、RM 内部处理提交阶段运行流程 如上图流程所示&#xff1a; 1.client 提交任务给yarn&#xff0c;yarn 这边会获取任务的AM相关资源&#xff0c;client在提交阶段会上传job.split &#xff08;数据切分…

Mysql-01-主从搭建

一、安装Mysql 下载 https://downloads.mysql.com/archives/community/ 安装 注意顺序 tar -xvf mysql-8.0.38-1.el9.x86_64.rpm-bundle.tar rpm -ivh mysql-community-common-8.0.38-1.el9.x86_64.rpm rpm -ivh mysql-community-client-plugins-8.0.38-1.el9.x86_64.r…

Vue3重构案例(使用vue3的语法重构element的button组件)

这篇文章紧接的上一篇文章&#xff0c;上篇文章是对给element的button组件写了一个单元测试&#xff0c;这篇文章是使用vue3的语法进行重构&#xff0c;这里说一下单元测试和重构的联系&#xff0c;当你给组件写了单元测试之后&#xff0c;重构会减少你很多的debug时间&#xf…

jdk22+maven环境配置教程+idea的maven环境配置(Windows系统)

前言 jdk是Java开发必要的编程环境&#xff0c;idea是常用的Java开发工具&#xff0c;这里着重解释一下maven。 maven就是我们经常看见的pom.xml文件&#xff0c;maven有以下三点功能&#xff1a; 1.项目构建&#xff08;可以帮助我们更快速的打包、构建项目&#xff09; 2.依…

数据操作10-15题(30 天 Pandas 挑战)

数据操作 1. 相关知识点1.12 分组与连表1.13 排名 2. 题目2.10 第N高的薪水2.11 第二高的薪水2.12 部门工资最高的员工2.13 分数排名2.14 删除重复的电子邮箱2.15 每个产品在不同商店的价格 1. 相关知识点 1.12 分组与连表 分组max_salaryemployee.groupby(departmentId)[sal…