当前位置: 首页 > news >正文

类与对象(三)

💬 :如果你在阅读过程中有任何疑问或想要进一步探讨的内容,欢迎在评论区畅所欲言!我们一起学习、共同成长~!

👍 :如果你觉得这篇文章还不错,不妨顺手点个赞、加入收藏,并分享给更多的朋友噢~!


1.  static 成员

1.1 概念

C++ 里,声明为 static 的类成员被称作类的静态成员。

用 static 修饰的成员变量是静态成员变量。

特别注意:静态成员变量一定要在类外进行初始化。

用 static 修饰的成员函数是静态成员函数。

实现一个类,用于计算程序中创建出的类对象的数量:

#include <iostream>
using namespace std;

class A
{
public:
    A() { ++_scount; }
    A(const A& t) { ++_scount; }
    ~A() 
    { 
        --_scount; 
    }
    static int GetACount() 
    { 
        return _scount; 
    }
private:
    static int _scount;
};

int A::_scount = 0;
// 静态成员变量在类外进行初始化

void TestA()
{
    cout << A::GetACount() << endl;
    A a1, a2;   // 默认构造
    
    A a3(a1);
    // 用一个已存在的对象初始化同类新对象时自动调用拷贝构造函数

    cout << A::GetACount() << endl;
}

int main()
{
    TestA();
    return 0;
}

1.2 特性

  • 共享性:静态成员为所有类对象所共享,并不属于某个具体的对象,它存放在静态区。
  • 定义静态成员变量:静态成员变量必须在类外进行定义,并且在定义时不需要添加 static 关键字,类中仅仅是声明。
  • 访问方式:类静态成员既能使用 类名::静态成员 的方式访问,也可用 对象.静态成员 的方式访问。
  • 静态成员函数:静态成员函数没有隐藏的 this 指针,所以不能访问任何非静态成员。而非静态成员函数可以访问类的静态成员。
  • 访问限定:静态成员同样是类的成员,会受到 publicprotectedprivate 访问限定符的限制。

2. 友元

友元是 C++ 中一种突破封装的机制(破坏封装性,所以谨慎使用)。

友元主要分为友元函数和友元类。

2.1 友元函数

在 C++ 中重载 operator<< 和 operator>> 时,无法将其重载为成员函数。因为成员函数有隐含的 this 指针作为首个参数,若重载为成员函数,调用形式会变成 对象 << cout 或 对象 >> cin,与常用的 cout << 对象cin >> 对象 不符。所以需将它们重载为全局函数,让 cout 或 cin 作为首个形参。

但全局函数在类外,无法直接访问类的私有成员,而实现 operator<< 和 operator>> 又常需访问这些私有成员。

为解决该矛盾,C++ 引入友元机制。在类中声明 operator<< 和 operator>> 为友元函数,可使全局函数访问私有成员,从而在符合使用习惯的同时,实现输入输出流运算符的重载。

class ClassName 
{
    // 其他成员声明

    friend 返回类型 函数名(参数列表); 

    // 其他成员声明
};
#include <iostream>
using namespace std;

class Date
{
    friend ostream& operator<<(ostream& _cout, const Date& d);  
    // ostream&是输出流对象的引用,实现链式输出

    friend istream& operator>>(istream& _cin, Date& d);  
    // istream&是输入流对象的引用,实现链式输入

public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}

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

ostream& operator<<(ostream& _cout, const Date& d)
{
    _cout << d._year << "-" << d._month << "-" << d._day;
    return _cout;
}

istream& operator>>(istream& _cin, Date& d)
{
    _cin >> d._year;
    _cin >> d._month;
    _cin >> d._day;
    return _cin;
}

int main()
{
    Date d;
    cin >> d;
    cout << d << endl;
    return 0;
}

友元函数特性

  • 访问权限:友元函数可以访问类的 private 和 protected 成员,但它本身并不是类的成员函数。
  • const 修饰:友元函数不能使用 const 进行修饰。
  • 声明位置:友元函数可以在类定义的任意位置声明,不受类访问限定符的限制。
  • 多类友元:一个函数可以成为多个类的友元函数。
  • 调用原理:友元函数的调用原理与普通函数相同。

2.2 友元类

友元类的所有成员函数都能够成为另一个类的友元函数,从而可以访问该非友元类中的非公有成员。

#include <iostream>
using namespace std;

class Time
{
    friend class Date; 
    // 声明Date类为Time类的友元类,则在Date类中就可直接访问Time类中的非公有成员

public:
    Time(int hour = 0, int minute = 0, int second = 0)
        : _hour(hour)
        , _minute(minute)
        , _second(second)
    {}

private:
    int _hour;
    int _minute;
    int _second;
};

class Date
{
public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}

    void SetTimeOfDate(int hour, int minute, int second)
    {
        // 直接访问Time类私有成员变量
        _t._hour = hour;
        _t._minute = minute;
        _t._second = second;
    }

    void Print()
    {
        cout << "Date: " << _year << "-" << _month << "-" << _day << endl;
        cout << "Time: " << _t._hour << ":" << _t._minute << ":" << _t._second << endl;
    }

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

int main()
{
    Date date(2025, 3, 23);
    date.SetTimeOfDate(12, 30, 0);
    date.Print();

    return 0;
}

Date 类内部创建了一个 Time 类的对象 _t,又 Date 类已被声明为 Time 类的友元类,那么在 Date 类中可直接访问 Time 类私有成员变量 _hour_minute_second 。

友元关系

  • 单向性:友元关系不具有交换性。例如,若 Time 类声明 Date 类为其友元类,那么在 Date 类中可以直接访问 Time 类的私有成员变量,但在 Time 类中不能访问 Date 类的私有成员变量。
  • 不可传递:如果 B 是 A 的友元,C 是 B 的友元,并不能说明 C 是 A 的友元。
  • 不可继承:友元关系不能继承,在后续的继承部分会详细介绍。

3. 内部类

当一个类的定义嵌套于另一个类的内部时,处于内部的这个类被称作内部类。

内部类特性

  • 内部类是一个完全独立的类,它并不归属于外部类。
  • 外部类的对象无法直接访问内部类的成员。
  • 在访问内部类成员时,外部类遵循与其他普通类相同的访问规则,受到内部类自身访问限定符(如 public、protected、private)的约束,没有额外的特权可以绕过这些访问限制。
  • 内部类天生是其外部类的友元类。内部类可访问外部类的所有成员。
  • 定义位置:内部类可定义在外部类的 public / protected / private 区域。
  • 静态成员访问:内部类可直接访问外部类中的 static 成员,无需借助外部类的对象或类名。
  • 创建内部类对象:外部类 A,内部类 B,通过“ A::B 对象名; ”创建内部类对象。
  • 大小无关性sizeof(外部类) 的结果与内部类没有任何关系。
#include <iostream>
using namespace std;

class A
{
private:
    static int k;
    int h;

public:
    class B 
    {
    public:
        void foo(const A& a)  // 常量引用类型的 A 类对象作参数
        {
            // 访问外部类 A 的私有成员
            cout << k << endl; 
            cout << a.h << endl; 
        }
    };
};

int A::k = 1;

int main()
{
    A::B b;   // 创建内部类 B 的对象 b

    b.foo(A());   // 传入一个临时的 A 类对象

    return 0;
}


4. 再次理解类和对象

计算机仅能识别二进制数据,无法直接认识现实生活中的实体。

借助面向对象编程思想,可按以下步骤让计算机认识实体:

  • (1)实体抽象:用户从人为思想层面剖析现实实体的属性与功能。如明确洗衣机的容量、功率等属性,以及洗涤、脱水等功能。
  • (2)类的描述:人对实体有清晰认知后,通过 C++、Java、Python 等面向对象语言,将实体特征用类描述并输入计算机,定义类的成员变量(描述属性)和成员函数(实现功能)。
  • (3)对象实例化:计算机有了类的定义后,通过实例化创建具体对象。对象是类的具体呈现,拥有类的属性和方法,占据独立内存空间,此时计算机才真正认识实体。
  • (4)模拟现实:用户借助实例化的对象,调用其功能模拟现实实体行为,如操作洗衣机对象进行洗涤。

学习类和对象时,要明白类是对一类实体(对象)的抽象描述,定义属性和方法后形成新的自定义类型,利用该类型可实例化出具体对象,为计算机模拟现实提供工具。

相关文章:

  • uv - Getting Started 开始使用 [官方文档翻译]
  • 1.认识Excel
  • LRU算法实现
  • 学习 - C++ 全栈聊天项目(1)架构概述和登录界面
  • 内核编程十三:进程状态详解
  • leetcode 用队列模拟栈
  • S32K144外设实验(七):FTM输出多路互补带死区PWM
  • 【MySQL】监控MySQL
  • C++值传递和引用传递
  • 【AI学习笔记】AI造神时代的潘式理论与智能进化
  • 定长内存池原理及实现
  • 电脑干货:万能驱动--EasyDrv8
  • Go 语言封装邮件发送功能
  • 亮数据爬取API爬取亚马逊电商平台实战教程
  • Springboot应用配置github自动流部署 深入理解CI/CD:构建、测试和部署的自动化完整流程
  • 千变万化的卷积
  • HarmonyOS 之 @Require 装饰器自学指南
  • 字符串常量,数组和指针的不同形式
  • 2000-2019年各省地方财政契税数据
  • 记一次线上程序宕机问题分析【写 GC 日志导致进程挂起】
  • 三个字公司名字大全 必过/seo研究协会网
  • 网站后台无法访问/怎样创建一个自己的网站
  • 电子商务网站建设基础项目实训报告/百度seo搜索
  • 自助建站平台哪家好/成都高端品牌网站建设
  • 如何自己做跨境电商/长沙seo代理
  • 做网站的财务需求/网站推广优化