剖析【C++】——类和对象(下篇)——超详解——小白篇

目录

1.再谈构造函数

1.1 构造函数体赋值

1.2 初始化列表

1.3 explicit 关键字

2. Static成员

2.1 概念

2.2 特性

3. 友元

3.1 友元函数

3.2 友元类

3.3总结:

4. 内部类

1.概念

2.特性

示例代码:

代码分析

3.总结

5.再次理解类和对象

1. 抽象现实生活中的实体

2. 用类描述实体

3. 实例化对象

4. 总结类和对象的关系


1.再谈构造函数

1.1 构造函数体赋值

构造函数是用来初始化对象的特殊函数。当我们创建一个对象时,编译器会自动调用构造函数来给对象的成员变量赋值。

简单理解:当你买一个新手机,打开包装,这就像调用了构造函数。手机里的默认应用程序就像成员变量的初始值。这些默认应用虽然是预装的,但我们可以再安装新的应用,这相当于构造函数体内的赋值操作。

示例代码:

class MyClass {
public:
    int x;
    int y;
    MyClass(int a, int b) : x(a), y(b) {}  // 初始化列表
};

在上面的代码中,当我们创建一个 MyClass 对象时,比如 MyClass obj(10);,构造函数 MyClass(int value) 会被调用,x 会被赋值为 10。但是这个过程叫赋值,不叫初始化,因为我们可以在构造函数内多次赋值。

总结:构造函数体内的赋值可以多次进行,而初始化只能进行一次。

1.2 初始化列表

初始化列表 是另一种在创建对象时给成员变量赋初值的方法。这种方法更高效,因为它在对象创建时就直接赋值,而不是先创建对象然后再赋值。

简单理解:假设你买了一辆新车,初始化列表就像你在购车前已经决定好车的颜色、型号等,而不是买车后再去喷漆改装。

示例代码:

class MyClass {
public:
    int x;
    int y;
    MyClass(int a, int b) : x(a), y(b) {}  // 初始化列表
};

在上面的代码中,: x(a), y(b) 就是初始化列表,它在构造函数体执行之前完成成员变量的初始化。

注意事项

  1. 每个成员变量在初始化列表中只能出现一次。
  2. 以下成员必须在初始化列表中初始化:
    • 引用类型成员变量
    • const 成员变量
    • 自定义类型成员变量(如果该类没有默认构造函数)

示例代码:

class MyClass {
public:
    const int x;
    int &y;
    MyClass(int a, int &b) : x(a), y(b) {}  // 必须在初始化列表中初始化
};

在这段代码中,const int xint &y 必须在初始化列表中进行初始化,因为 const 成员变量和引用类型成员变量在对象创建时就需要确定其初始值。

总结:尽量使用初始化列表,因为它对自定义类型成员变量更高效。

1.3 explicit 关键字

构造函数不仅可以用来创建对象,还可以用来进行类型转换。对于只有一个参数的构造函数,如果不使用 explicit 关键字,编译器会自动进行隐式类型转换。

简单理解:假设有一个银行系统,你有一个账户类。如果允许隐式转换,就像允许陌生人随意把你的银行账号转换成他们的账户,这很危险。所以我们需要 explicit 关键字来禁止这种转换。

示例代码:

class MyClass {
public:
    int x;
    explicit MyClass(int value) : x(value) {}  // 使用 explicit 关键字
};

void func(MyClass obj) {
    // do something
}

int main() {
    MyClass obj1(10);  // 正常调用构造函数
    // MyClass obj2 = 10;  // 错误,explicit 禁止隐式转换
    // func(20);  // 错误,explicit 禁止隐式转换
    return 0;
}

在上面的代码中,explicit 关键字禁止了构造函数的隐式转换,这样可以避免潜在的错误和提高代码的可读性。

总结:使用 explicit 关键字可以防止构造函数被用于隐式转换,确保代码的安全性和可读性。

2. Static成员

2.1 概念

在C++中,声明为static的类成员称为类的静态成员。静态成员分为静态成员变量和静态成员函数。

  • 静态成员变量:用static修饰的成员变量。
  • 静态成员函数:用static修饰的成员函数。

简单理解:静态成员就像学校里的公共设施,比如学校的大门(静态成员变量)和学校的公告栏(静态成员函数),它们是所有学生(类的对象)共享的,而不是某个学生独有的。

初始化:静态成员变量必须在类外进行初始化。

面试题:实现一个类,计算程序中创建了多少个类对象。

示例代码

#include <iostream>
using namespace std;

class MyClass {
public:
    static int count;  // 静态成员变量声明

    MyClass() {
        count++;  // 每创建一个对象,count加1
    }

    // 静态成员函数
    static int getCount() {
        return count;
    }
};

// 静态成员变量在类外定义并初始化
int MyClass::count = 0;

int main() {
    MyClass obj1;
    MyClass obj2;
    MyClass obj3;
    cout << "Created objects: " << MyClass::getCount() << endl;
    return 0;
}

在这段代码中,MyClass类的静态成员变量count记录了创建的对象数量,每创建一个对象,count就加1。静态成员函数getCount返回当前的对象数量。

2.2 特性

  1. 静态成员为所有类对象共享:静态成员变量存放在静态区,不属于某个具体的对象。
  2. 静态成员变量必须在类外定义:定义时不添加static关键字,类中只是声明。
  3. 访问静态成员:静态成员可以通过类名::静态成员对象.静态成员访问。
  4. 静态成员函数没有this指针:不能访问任何非静态成员。
  5. 静态成员受访问限定符限制:静态成员同样受publicprotectedprivate访问限定符的限制。

示例代码

class MyClass {
public:
    static int staticVar;  // 静态成员变量声明
    int nonStaticVar;      // 非静态成员变量

    static void staticFunc() {
        // 静态成员函数不能访问非静态成员
        // cout << nonStaticVar;  // 错误
        cout << staticVar;  // 正确
    }

    void nonStaticFunc() {
        cout << staticVar;  // 非静态成员函数可以访问静态成员
        cout << nonStaticVar;  // 非静态成员函数可以访问非静态成员
    }
};

// 静态成员变量定义
int MyClass::staticVar = 0;

问题解答

1.静态成员函数可以调用非静态成员函数吗? 不可以。静态成员函数没有this指针,所以不能访问类的非静态成员(包括非静态成员函数)。

示例代码

class MyClass {
public:
    static void staticFunc() {
        // nonStaticFunc();  // 错误,静态成员函数不能调用非静态成员函数
    }

    void nonStaticFunc() {
        cout << "Non-static member function called." << endl;
    }
};

2.非静态成员函数可以调用类的静态成员函数吗? 可以。非静态成员函数可以访问类的所有成员,包括静态成员。

示例代码

class MyClass {
public:
    static void staticFunc() {
        cout << "Static member function called." << endl;
    }

    void nonStaticFunc() {
        staticFunc();  // 非静态成员函数可以调用静态成员函数
    }
};

3. 友元

友元提供了一种特殊的机制,可以让一个类允许另一个类或函数访问其私有或受保护的成员。虽然友元增加了便利性,但也会破坏封装性,增加代码耦合度,因此使用时需谨慎。

3.1 友元函数

问题描述:在重载 operator<< 时,无法将其重载为成员函数,因为 cout 作为输出流对象和 this 指针会竞争第一个参数的位置。为了使 cout 成为第一个参数,我们需要将 operator<< 重载为全局函数。但全局函数不能直接访问类的私有成员,这时就需要友元函数来解决这个问题。

友元函数的特点

  1. 可以访问类的私有和保护成员,但不属于类的成员函数。
  2. 不能用 const 修饰。
  3. 可以在类定义的任何地方声明,不受类访问限定符限制。
  4. 一个函数可以是多个类的友元函数。
  5. 友元函数的调用与普通函数的调用相同。

示例代码

#include <iostream>
using namespace std;

class MyClass {
private:
    int value;

public:
    MyClass(int v) : value(v) {}

    // 声明友元函数
    friend ostream& operator<<(ostream& os, const MyClass& obj);
};

// 定义友元函数
ostream& operator<<(ostream& os, const MyClass& obj) {
    os << obj.value;
    return os;
}

int main() {
    MyClass obj(42);
    cout << obj << endl;  // 输出: 42
    return 0;
}

在上面的代码中,operator<< 被定义为友元函数,因此它可以访问 MyClass 类的私有成员 value

3.2 友元类

友元类是一种类的所有成员函数都可以访问另一个类的私有和保护成员的机制。

特点

  1. 友元关系是单向的,不具有交换性。例如,如果 A 类是 B 类的友元,那么 B 类可以访问 A 类的私有成员,但反过来 A 类不能访问 B 类的私有成员。
  2. 友元关系不能传递。如果 BA 的友元,而 CB 的友元,这并不意味着 CA 的友元。
  3. 友元关系不能继承。

示例代码

#include <iostream>
using namespace std;

class Date;

class Time {
private:
    int hour;
    int minute;

public:
    Time(int h, int m) : hour(h), minute(m) {}

    // 声明Date类为友元类
    friend class Date;
};

class Date {
private:
    int day;
    int month;
    int year;

public:
    Date(int d, int m, int y) : day(d), month(m), year(y) {}

    void displayTime(const Time& t) {
        // 访问Time类的私有成员
        cout << "Time: " << t.hour << ":" << t.minute << endl;
    }
};

int main() {
    Time t(10, 30);
    Date d(1, 5, 2023);
    d.displayTime(t);  // 输出: Time: 10:30
    return 0;
}

在上面的代码中,Date 类被声明为 Time 类的友元类,因此 Date 类的成员函数可以访问 Time 类的私有成员。

3.3总结

  • 友元函数和友元类允许访问私有和保护成员,但要谨慎使用,因为这会增加代码的耦合性。
  • 友元关系是单向的,不可传递。
  • 使用友元可以解决一些特殊情况下的访问权限问题,如重载运算符等。

4. 内部类

1.概念

内部类 是指定义在另一个类内部的类。它是一个独立的类,不属于外部类,不能通过外部类的对象访问其成员。

简单理解:就像一家大公司的部门(内部类)和公司(外部类),部门是独立的,但仍然是公司的一部分,外部类对内部类没有特别的访问权限。

注意事项

  • 内部类就像是外部类的友元类,内部类可以通过外部类的对象参数访问外部类的所有成员。
  • 外部类对内部类没有友元访问权限,不能访问内部类的私有成员。

2.特性

  1. 内部类的位置:内部类可以定义在外部类的 publicprotectedprivate 区域。
  2. 访问外部类的静态成员:内部类可以直接访问外部类的静态成员,而不需要外部类的对象或类名。
  3. 大小计算sizeof(外部类) 只计算外部类的大小,与内部类无关。

示例代码:

#include <iostream>
using namespace std;

class OuterClass {
private:
    int outerVar;
    static int outerStaticVar;

public:
    OuterClass(int val) : outerVar(val) {}

    // 定义内部类
    class InnerClass {
    public:
        void displayOuter(OuterClass& outer) {
            // 访问外部类的非静态成员需要外部类的对象
            cout << "Outer class non-static member: " << outer.outerVar << endl;
        }

        void displayOuterStatic() {
            // 直接访问外部类的静态成员
            cout << "Outer class static member: " << outerStaticVar << endl;
        }
    };

    // 外部类中的成员函数可以创建内部类的对象
    void createInner() {
        InnerClass inner;
        inner.displayOuter(*this);
        inner.displayOuterStatic();
    }
};

// 定义并初始化外部类的静态成员
int OuterClass::outerStaticVar = 10;

int main() {
    OuterClass outer(5);
    outer.createInner();

    // 外部类对象不能直接访问内部类成员
    // outer.InnerClass inner;  // 错误

    // 创建内部类对象
    OuterClass::InnerClass inner;
    inner.displayOuter(outer);
    inner.displayOuterStatic();

    return 0;
}

代码分析

  1. 内部类的位置InnerClass 定义在 OuterClasspublic 区域内,可以访问外部类的静态和非静态成员。
  2. 访问外部类的静态成员InnerClass 中的 displayOuterStatic 函数直接访问 OuterClass 的静态成员 outerStaticVar
  3. 访问外部类的非静态成员displayOuter 函数通过 OuterClass 的对象参数 outer 访问其非静态成员 outerVar

3.总结

  • 内部类 是独立的类,可以定义在外部类的任何访问区域。
  • 内部类可以直接访问外部类的静态成员,不需要外部类的对象或类名。
  • 内部类可以通过外部类的对象参数访问外部类的非静态成员。
  • 外部类不能访问内部类的私有成员,内部类也不会影响外部类的大小计算。

5.再次理解类和对象

1. 抽象现实生活中的实体

在现实生活中,计算机无法直接认识物理世界中的实体,如洗衣机。为了让计算机理解这些实体,我们需要通过面向对象的语言(如C++)对它们进行抽象和描述。

简单理解:假设你想让计算机认识洗衣机。首先,你需要在头脑中抽象出洗衣机的属性和功能。比如,洗衣机有颜色、品牌、容量等属性,还有启动、停止、洗涤等功能。

2. 用类描述实体

一旦你在人为思想层面对洗衣机有了清晰的认识,就需要用某种编程语言(如C++)将这种认识转化为计算机能理解的格式。我们使用“类”来描述洗衣机。

示例代码

class WashingMachine {
public:
    // 属性
    string color;
    string brand;
    int capacity;

    // 方法
    void start() {
        cout << "Washing machine started." << endl;
    }

    void stop() {
        cout << "Washing machine stopped." << endl;
    }

    void wash() {
        cout << "Washing machine is washing clothes." << endl;
    }
};

在上面的代码中,我们定义了一个类 WashingMachine,它包含了洗衣机的属性(颜色、品牌、容量)和方法(启动、停止、洗涤)。

3. 实例化对象

定义了类之后,计算机还不能理解洗衣机是什么。我们需要通过类来实例化具体的洗衣机对象。

示例代码

int main() {
    // 实例化一个洗衣机对象
    WashingMachine myWasher;

    // 给属性赋值
    myWasher.color = "White";
    myWasher.brand = "LG";
    myWasher.capacity = 7;

    // 调用方法
    myWasher.start();
    myWasher.wash();
    myWasher.stop();

    return 0;
}

在这段代码中,我们创建了一个 WashingMachine 对象 myWasher,并为其属性赋值,然后调用其方法来模拟洗衣机的行为。

4. 总结类和对象的关系

是对某一类实体的抽象和描述。类定义了这些实体具有的属性和方法,形成了一种新的自定义类型。

对象 是类的实例,是具体的实体。通过实例化类,我们创建对象,然后可以使用这些对象来模拟现实中的实体。

现实生活中的模拟

  • 抽象:你在人为思想层面对洗衣机进行认识,确定它的属性和功能。
  • :用C++类来描述洗衣机的属性和功能,将这种描述输入计算机中。
  • 实例化:通过类实例化具体的洗衣机对象,计算机才真正理解和模拟洗衣机的行为。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vue-esign实现电子签名

导入依赖 pnpm install vue-esign --savesign.vue代码实现 <template><div id"app"><div class"signMask" v-if"autographStatus"><div class"sigh-btns"><button class"btn" type"info&…

mysql中子查询的语法和执行过程

大家好。我们在日常开发过程中&#xff0c;肯定都经常用到了子查询。今天我们就来聊一下mysql中子查询的一些语法以及子查询的执行过程。 一、子查询的语法 首先在开讲之前&#xff0c;我们先创建t1、t2两张表&#xff0c;并分别在表中插入三条数据&#xff0c;方便我们下面内…

269 基于matlab的四连杆机构动力学参数计算

基于matlab的四连杆机构动力学参数计算。将抽油机简化为4连杆机构&#xff0c;仿真出悬点的位移、速度、加速度、扭矩因数、游梁转角等参数&#xff0c;并绘出图形。程序已调通&#xff0c;可直接运行。 269机构动力学参数计算 位移、速度、加速度 - 小红书 (xiaohongshu.com)

校园志愿者|基于SprinBoot+vue的校园志愿者管理系统(源码+数据库+文档)

校园志愿者管理系统 目录 基于SprinBootvue的校园志愿者管理系统 一、前言 二、系统设计 三、系统功能设计 1 系统功能模块 2管理员功能 3志愿者功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&a…

多维时序 | Matlab实现SA-BP模拟退火算法优化BP神经网络多变量时间序列预测

多维时序 | Matlab实现SA-BP模拟退火算法优化BP神经网络多变量时间序列预测 目录 多维时序 | Matlab实现SA-BP模拟退火算法优化BP神经网络多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现SA-BP模拟退火算法优化BP神经网络多变量时间序列预…

pyinstaller将py文件打包成exe

pyinstaller将py文件打包成exe 一、为什么需要将python文件打包成exe文件?二、具体操作步骤一、为什么需要将python文件打包成exe文件? python文件需要在python环境中运行,也就是需要安装python解释器。有时我们自己写的python程序需要分享给自己的朋友、同事或者合作伙伴,…

【xilinx】vivado中的xpm_cdc_gray.tcl的用途

背景 【Xilinx】vivado methodology检查中出现的critical Warning-CSDN博客 接上篇文章&#xff0c;在vivado进行 methodology检查时出现了严重警告&#xff0c;顺着指示查到如下一些问题 TIMING #1 Warning An asynchronous set_clock_groups or a set_false path (see con…

【SAP HANA 33】前端参数多选情况下HANA如何使用IN来匹配?

场面描述: 在操作界面经常会出现某个文本框需要多选的情况,然后后台需要根据多选的值进行匹配搜索。 一般处理的情况是: 1、在Java后端动态生成SQL 2、不改变动态SQL的情况,直接当做一个正常的参数进行传递 本次方案是第二个,直接当做一个正常的字符串参数进行传递即…

海康威视综合安防管理平台 orgManage/v1/orgs/download 任意文件读取漏洞复现

0x01 产品简介 海康威视综合安防管理平台是一套“集成化”、“智能化”的平台,通过接入视频监控、一卡通、停车场、报警检测等系统的设备。海康威视集成化综合管理软件平台,可以对接入的视频监控点集中管理,实现统一部署、统一配置、统一管理和统一调度。 0x02 漏洞概述 海康…

python对文本操作,生成可执行文件

.exe文件主要包含pingmianF.py文件和read_inp_auto.py文件 实现效果 代码 read_inp_auto.py #-*- coding: utf-8 -*- import re import sys import os import os.path import time import pingmianF from pingmianF import vector import numpy as np from tkinter import me…

SNCScan:针对SAP安全网络通信(SNC)的安全分析与评估工具

关于SNCScan SNCScan是一款针对SAP安全网络通信&#xff08;SNC&#xff09;的安全分析与评估工具&#xff0c;该工具旨在帮助广大研究人员分析SAP安全网络通信&#xff08;SNC&#xff09;&#xff0c;并分析和检测SNC配置与SAP组件中的潜在问题。 SNC系统参数 SNC基础 SAP协…

软件磁盘阵列与LVM

一、软件磁盘阵列 磁盘阵列&#xff08;RAID&#xff09;是通过硬件或软件技术将多个较小的磁盘整合成为一个较大的磁盘设备&#xff0c;而这个较大的磁盘除了存储还具备数据保护功能。 RAID分不同的级别&#xff0c;不同级别具有不同功能&#xff1a; 1、RAID 0&#xff1a;…

摸鱼大数据——select查询7-10

7、union联合查询 union: 对重复数据会去重 union all: 对重复数据不会去重 ​ 注意&#xff1a;union和union all中两边的字段&#xff08;类型、顺序&#xff09;要对应上 示例: use day08; select * from students; ​ select id,name from students where id in (95001,9…

读天才与算法:人脑与AI的数学思维笔记26_读后总结与感想兼导读

1. 基本信息 天才与算法&#xff1a;人脑与AI的数学思维 [英] 马库斯杜索托伊 &#xff08;Marcus du Sautoy&#xff09; 机械工业出版社,2020年4月出版 1.1. 读薄率 书籍总字数284千字&#xff0c;笔记总字数39047字。 读薄率39047284000≈13.7% 1.2. 读厚方向 千脑智…

Python—面向对象小解(3)

一、多态 多态指的是一类事物的多中形态 相同的方法&#xff0c;产生不同的执行结果 运算符 * 的多态 int int 加法计算 str str 字符串拼接 list list 列表的数据合并 在python中可以使用类实现一个多态效果 在python中使用重写的方式实现多态 &#xff08;1&#xff09;定…

Git-lfs入门使用教程

在备份我的毕设到github私有库的时候&#xff0c;发现git对于单文件大于100MB的会限制上传&#xff0c;一番折腾一下发现了git-lfs [Git LFS&#xff08;Large File Storage,大文件存储&#xff09;是 Github 开发的一个Git 的扩展&#xff0c;用于实现 Git 对大文件的支持]。 …

【效率提升】谷歌浏览器搜索技巧

文章目录 查找快速解答&#xff0c;以关键词形式进行搜索使用搜索运算符限定搜索范围&#xff0c;排除不相干内容使用高级搜索&#xff0c;可以搜索到更详细、具体、专业的结果 查找快速解答&#xff0c;以关键词形式进行搜索 想要哪个领域的快速解答&#xff0c;就使用哪个领…

星鸾云平台:高效配置Anaconda环境

星鸾云平台&#xff1a;高效配置Anaconda环境 多种算力资源和AI一体机在星鸾云平台上安装Anaconda并配置Python环境的步骤注册和登录体验GPU显卡服务选择服务器实例登陆GPU实例挂载数据盘配置CUDA环境安装Anaconda 星鸾云平台的优势 星鸾云平台以其卓越的产品功能和优势&#x…

期权交易有什么利弊点?

今天带你了解期权交易有什么利弊点&#xff1f;期权是一种合约&#xff0c;有看涨期权和看跌期权两种类型&#xff0c;也就是做多和做空两个方向&#xff0c;走势标的物对应大盘指数&#xff0c;这也是期权与其他金融工具的主要区别之一&#xff0c;可以用于套利&#xff0c;对…

Python中限制输入数值范围的技术性探讨

目录 一、引言 二、使用内置函数限制输入范围 三、使用条件语句进行范围检查 四、使用异常处理增强鲁棒性 五、结合第三方库进行输入验证 六、总结 一、引言 在Python编程中&#xff0c;用户输入是程序与用户交互的重要方式之一。然而&#xff0c;由于用户输入的多样…