【C++初阶】类和对象(下)

【C++初阶】类和对象下

🥕个人主页:开敲🍉

🔥所属专栏:C++🥭

🌼文章目录🌼

1. 再谈构造函数

2. 类型转换

3. static成员

4. 友元

5. 内部类

1. 再谈构造函数

 之前我们实现构造函数时,初始化成员变量主要使用函数体内赋值,构造函数初始化还有一种方式,就是初始化列表,初始化列表的使用方式是以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟⼀个放在括号中的初始值或表达式。

 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。 

 引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进行初始化,否则会编译报错。

 C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员使用的。

 尽量使用初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显示在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。

⑥ 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。

  没有默认构造的自定义类类型变量、static修饰的变量和引用变量必须在初始化列表中初始化,否则会报错。

错误:

正确:

  下面再来看一段代码

  思考一下,上面那里是初始化吗?

  注意:上面那里不是初始化,而是给一个缺省值,这个缺省值是给到初始化列表的。如果在初始化时给定了一个值,那么就会初始化为这个值;如果没给,则会默认使用这个缺省值初始化。

  来看看下面一段代码的输出结果是什么:

A. 输出1 1  B. 输出2  2   C. 编译报错  D. 输出1 随机值  E. 输出1  2  F. 输出2  1

答案:D

解释:初始化的顺序是根据声明的顺序来的,这里我们先声明的是_a2,因此我们在初始化时也是会先初始化_a2,而_a2又是由_a1初始化,但是_a1我们还并没有初始化,因此_a1是随机值,所以_a2会被初始化为随机值;而后初始化_a1,_a1是由参数a初始化的,因此_a1初始化为1,故答案为D。

2. 类型转换

 C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数

 构造函数前⾯加explicit就不再⽀持隐式类型转换

#include<iostream>
using namespace std;
class A
{
public:
    // 构造函数explicit就不再支持隐式类型转换
    // explicit A(int a1)
    A(int a1)
        : _a1(a1)
    {}
    //explicit A(int a1, int a2)
    A(int a1, int a2)
        :_a1(a1)
        , _a2(a2)
    {}
    void Print()
    {
        cout << _a1 << " " << _a2 << endl;
    }
private:
    int _a1 = 1;
    int _a2 = 2;
};
int main()
{
    // 1构造⼀个A的临时对象,再用这个临时对象拷贝构造aa3
    // 编译器遇到连续构造+拷贝构造->优化为直接构造

    A aa1 = 1;
    aa1.Print();
    const A& aa2 = 1;
    // C++11之后才支持多参数转化
    A aa3 = { 2,2 };
    return 0;
}

3. static成员

 ⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进行初始化。

 静态成员变量不能在声明位置给缺省值初始化,因为缺省值是走构造函数初始化列表来初始化的,静态成员变量不属于某个对象,不走构造函数初始化列表。

错误:

练习题:求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com)

//思路:利用每次创建类类型对象都会调用构造函数的特点,我们在构造函数中完成等差数列累加功能。这里需要创建一个类类型的变长数组,用于多次创建类类型对象。

//用于完成等差数列的累加

class Sum

{

public:

//每次创建类类型对象都会调用构造函数,因此创建一个构造函数,在构造函数中完成

//等差数列累加的功能

//特别的:这里需要使用静态变量

//上面说过,类内声明的static变量必须在类外进行定义

    Sum()

    {

        x+=y;

        y++;

    }

    static int GetX()

    {

        return x;

    }

private:

    static int x;

    static int y;

};

int Sum::x = 0;

int Sum::y = 1;

class Solution {

public:

    int Sum_Solution(int n)

    {

//Sum类的变长数组,用于多次创建类类型对象

        Sum arr[n];

        return Sum::GetX();

    }

};

  再来看看下面的两个问题:

设已经有A、B、C、D四个类的定义,程序中A、B、C、D构造函数调用顺序为?()

 设已经有A、B、C、D四个类的定义,程序中A、B、C、D析构函数调用顺序为?()

C c;

int main()
{
    A a;
    B b;
    static D d;
    return 0;
}

A. D   B   A   C

B. B   A   D   C

C. C   D   B   A

D. A   B   D   C

E. C   A   B   D

F. C   D   A   B

答案:E、B

解析:构造函数调用顺序:C是全局类,因此程序在运行时肯定是最先调用C的构造函数;随后从上到下依次调用A、B、D的构造函数,故顺序为C-->A-->B-->D。析构函数调用顺序:析构函数调用看的是类的生命周期,A和B都是局部对象,因此生命周期仅存在于当前函数,当函数结束时,最先调用B的析构函数(因为需要满足后构造的先析构),然后是A。虽然D和C的生命周期相同,但由于D后于C构造,因此D先调用析构函数,最后是C,故顺序为B-->A-->D-->C。

4. 友元

 友元提供了一种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到⼀个类的里面。

 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。

 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。

 ⼀个函数可以是多个类的友元函数。

 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。

 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。

 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是B的友元。

 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

  友元函数声明:

  友元类声明:

class Date
{
public:
    //友元函数声明
    friend void Printf(const Date& d);
    //友元类声明
    friend class Time;
    Date(int year, int month, int day)
        //初始化列表
        :_year(year)
        , _month(month)
        , _day(day)
    {}
    int GetTimeHour()
    {
    }
    void Printf()
    {
        cout << _year << "/" << _month << "/" << _day << endl;
    }
private:
    int _year;
    int _month;
    int _day;
};

class Time
{
public:
    Time(int hour, int minute, int second)
    {
        _hour = hour;
        _minute = minute;
        _second = second;
    }
    int GetDateYear(const Date& d)
    {
        return d._year;
    }
    int GetDateMonth(const Date& d)
    {
        return d._month;
    }
    int GetDateDay(const Date& d)
    {
        return d._day;
    }
private:
    int _hour;
    int _minute;
    int _second;
};


void Printf(const Date& d)
{
    cout << d._year << "/" << d._month << "/" << d._day << endl;
}


int main()
{
    Date d1(2024, 7, 14);
    Time t1(1, 1, 1);
    cout << t1.GetDateYear(d1) << "/" << t1.GetDateMonth(d1) << "/" << t1.GetDateDay(d1) << endl;
    d1.Printf();
    Printf(d1);
    return 0;
}

5. 内部类

 如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

 内部类默认是外部类的友元类。

 内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。

  例如上面的练习题我们还可以写成:

#include <valarray>
class Solution {
public:

//内部类
class SL
{
public:
    SL()
    {
        x+=y;
        y++;
    }
};
    int Sum_Solution(int n) 
    {
        SL arr[n];
        return x;
    }
private:
    static int x;
    static int y;
};

int Solution::x = 0;
int Solution::y = 1;

  这里的SL就是内部类。因为内部类默认是外部类的友元函数,因此我们就可以将static变量写在Solution类中,SL函数中一样可以调用。

                                           创作不易,点个赞呗,蟹蟹啦~

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

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

相关文章

关于Qt Creator 使用Qt Quick的Design模式设置

关于使用Qt Quick的Design模式设置&#xff1a; 如描述所言&#xff1a; 如果使用Design模式打开qml文件失败显示如下&#xff1a; 首先确认自己是否安装了Qt Design Studio 如果安装了仍然不显示&#xff0c;则需要勾选下面三个地方才能用Design模式打开.ui.qml文件&#…

gradle设置优先使用maven本地仓库

1. gradle优先使用maven本地库的逻辑 Created with Raphal 2.3.0 开始 maven本地库 是否存在依赖&#xff1f; 使用maven 本地库的依赖 结束 下载依赖到 gradle本地库 yes no 2. 配置 在app/build.gradle.kts中添加mavenLocal() mavenLocal()9. 参考文章 https://www.cnblog…

24_YOLOV3-SPP网络详解

1.1 简介 YOLOv3-SPP是对YOLOv3&#xff08;You Only Look Once version 3&#xff09;目标检测模型的一种改进版本&#xff0c;其中"SPP"代表空间金字塔池化&#xff08;Spatial Pyramid Pooling&#xff09;。这个改进主要是为了增强网络对不同尺度物体的检测能力…

Qt5离线安装包无法下载问题解决办法

Qt5离线安装包无法下载问题解决办法 文章目录 Qt5离线安装包无法下载问题解决办法1、前言2、Qt5安装包下载办法 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;Qt开发经验 &#x1f448; 1、前言 Qt安装包官方下载地址 Qt5离线安装包目前在国内已经被墙…

Golang | Leetcode Golang题解之第233题数字1的个数

题目&#xff1a; 题解&#xff1a; func countDigitOne(n int) (ans int) {// mulk 表示 10^k// 在下面的代码中&#xff0c;可以发现 k 并没有被直接使用到&#xff08;都是使用 10^k&#xff09;// 但为了让代码看起来更加直观&#xff0c;这里保留了 kfor k, mulk : 0, 1;…

大模型系列3--pytorch dataloader的原理

pytorch dataloader运行原理 1. 背景2. 环境搭建2.1. 安装WSL & vscode2.2. 安装conda & pytorch_gpu环境 & pytorch 2.112.3 命令行验证python环境2.4. vscode启用pytorch_cpu虚拟环境 3. 调试工具3.1. vscode 断点调试3.2. py-spy代码栈探测3.3. gdb attach3.4. …

IDEA社区版使用Maven archetype 创建Spring boot 项目

1.新建new project 2.选择Maven Archetype 3.命名name 4.选择存储地址 5.选择jdk版本 6.Archetype使用webapp 7.create创建项目 创建好长这样。 检查一下自己的Maven是否是自己的。 没问题的话就开始增添java包。 [有的人连resources包也没有&#xff0c;那就需要自己添…

每日一题~ cf div3 957 D+E(若只dp,暴力枚举)

D题 简单的dp&#xff0c;我当时没反应过来 这是 dp&#xff0c;好吧&#xff0c;其实是很久没做题了。&#xff08;脑袋木了&#xff09; 题意&#xff1a;n m k n 长的字符 &#xff0c;m k 可以跳跃的最大距离&#xff08;每次跳跃的距离1< <m) k 在水里游泳的最大值 …

IP 地址与 CDN 性能优化

内容分发网络&#xff08;CDN&#xff09;就是通过内容分配到离用户最优的服务器来提高访问速度。而IP地址如何分配与管理就是CND技术的基础。本文将来探讨介绍CDN中的IP地址分配与管理&#xff0c;以及如何通过CDN优化网络性能。 首先我们来了解CDN的基本原理 CDN是一种分布式…

Java核心篇之JVM探秘:内存模型与管理初探

系列文章目录 第一章 Java核心篇之JVM探秘&#xff1a;内存模型与管理初探 第二章 Java核心篇之JVM探秘&#xff1a;对象创建与内存分配机制 第三章 Java核心篇之JVM探秘&#xff1a;垃圾回收算法与垃圾收集器 第四章 Java核心篇之JVM调优实战&#xff1a;Arthas工具使用及…

基于Java中的SSM框架实现暖心家装平台系统项目【项目源码+论文说明】

基于Java中的SSM框架实现暖心家装平台系统演示 摘要 自从互联网技术得到大规模的应用以后&#xff0c;传统家装企业面临全新的竞争激烈的市场环境。要想占得当前家装营销与管理的先机&#xff0c;除了要加强内部管理&#xff0c;提高企业内部运营效率&#xff0c;更要积极推进…

google 浏览器插件开发简单学习案例:计算器

1、首先&#xff0c;我们需要创建扩展的文件结构 2、创建 manifest.json 文件 是Chrome插件的配置文件&#xff0c;定义了插件的基本信息和资源。 {"manifest_version": 3,"name": "Simple Calculator","version": "1.0"…

[K8S]一、Flink on K8S

Kubernetes | Apache Flink 先编辑好这5个配置文件&#xff0c;然后再直接执行 kubectl create -f ./ kubectl get all kubectl get nodes kubectl get pods kubectl get pod -o wide kubectl get cm -- 获取所有的configmap 配置文件 kubectl logs pod_name -- 查看…

链接追踪系列-00.es设置日志保存7天-番外篇

索引生命周期策略 ELK日志我们一般都是按天存储&#xff0c;例如索引名为"zipkin-span-2023-03-24"&#xff0c;因为日志量所占的存储是非常大的&#xff0c;我们不能一直保存&#xff0c;而是要定期清理旧的&#xff0c;这里就以保留7天日志为例。 自动清理7天以前…

Java二十三种设计模式-工厂方法模式(2/23)

工厂方法模式&#xff1a;设计模式中的瑞士军刀 引言 在软件开发中&#xff0c;工厂方法模式是一种常用的创建型设计模式&#xff0c;它用于处理对象的创建&#xff0c;将对象的实例化推迟到子类中进行。这种模式不仅简化了对象的创建过程&#xff0c;还提高了代码的可维护性…

如何预防最新的baxia变种勒索病毒感染您的计算机?

引言 在当今数字化时代&#xff0c;网络安全威胁层出不穷&#xff0c;其中勒索病毒已成为企业和个人面临的重大挑战之一。近期&#xff0c;.baxia勒索病毒以其高隐蔽性和破坏性引起了广泛关注。本文将详细介绍.baxia勒索病毒的特点、传播方式&#xff0c;并给出相应的应对策略…

QT VTK 简单测试工程

目录 1 目录结构 2 文件源码 3 运行结果 4 报错及处理 使用编译好的VTK库进行测试 1 目录结构 2 文件源码 Pro文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c17# You can make your code fail to compile if it uses deprecated APIs. #…

今天我们来聊Java IO模型,BIO、NIO、AIO三种常见IO模型

一、写在开头 很久没更新喽&#xff0c;最近build哥一直在忙着工作&#xff0c;忙着写小说&#xff0c;都忘记学习自己的本职了&#xff0c;哈哈&#xff0c;不过现在正式回归&#xff01; 我们继续学习Java的IO相关内容&#xff0c;之前我们了解到&#xff0c;所谓的IO&#…

工作笔记 5 Post请求 密码加密器PasswordEncoder 小程序登录

1.微信小程序登录 1.1小程序登录流程图 1.2使用sa-token完成登录 参考csdn这位老哥的http://t.csdnimg.cn/oRgvI sa-token是一款轻量级的安全框架 1.2.1首先引入sa-token依赖 <dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring…

java日常开发中常用的集合工具类方法归总(java8 stream)

1、创建map集合的方式 方式1&#xff1a; Map<String, Object> map new HashMap<>(); map.put("a", "test"); map.put("b", "since"); 方式2&#xff1a; Map<String, Object> map2 new HashMap<>() {{…