【C++】类与对象(四)——初始化列表|explicit关键字|static成员|友元|匿名对象

news2024/11/15 8:24:42

在这里插入图片描述

前言:
初始化列表,explicit关键字,static成员,友元,匿名对象


文章目录

  • 一、构造函数的初始化列表
    • 1.1 构造函数体内赋值
    • 1.2 初始化列表
  • 二、explicit关键字
  • 三、static成员
  • 四、友元
    • 4.1 友元函数
    • 4.2 友元类
  • 五、内部类
  • 六、匿名对象

一、构造函数的初始化列表

1.1 构造函数体内赋值

class Date{
public:
	Date(int year, int month, int day){
		//赋值,并非初始化
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};

构造函数调用之后,在函数体中给成员变量赋值,但这并不能称为初始化,因为初始化是在变量或对象的创建时进行的,如果有初始化,那么仅有一次只有一次,而构造函数体内可以多次赋值。

对于某些类型的成员变量,必须进行初始化。函数体内并不能满足这些类型的成员变量进行初始化,因此有了初始化列表的概念。


1.2 初始化列表

初始化列表用于在构造函数中初始化类成员变量的语法结构:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。

_year _month _day被year,month,day进行初始化

Date(int year, int month, int day) :
		_year(year), 
		_month(month), 
		_day(day) {
		//函数体内其他操作
}	
  1. 实际上,即使没有显式写出初始化列表,成员变量依然会走初始化列表,但是因为没有初始值,因此成员变量是默认值。且初始化列表的顺序是成员变量声明的顺序。
    在这里插入图片描述

  2. 以下成员,必须放在初始化列表位置进行初始化

    • 引用成员变量
    • const成员变量
    • 自定义类型成员(且该类没有默认构造函数时)
    class A{
    public:
    	A(int a):_a(a){
    
    	}
    private:
    	int _a;
    };
    
    class B{
    private:
    	A _aobj;      // 自定义类型且没有默认构造函数
    	int& _ref;    // 引用
    	const int _n; // const 
    public:
    	// _aobj(a)可以理解为调用A类的构造函数
    	B(int a, int ref):_aobj(a), _ref(ref), _n(0){
    		// 其他操作
    	}
    };
    
    int main() {               
    	B b(10,5);
    	return 0;
    }
    
  3. 成员变量声明时提供缺值
    当成员变量没有在初始化列表初始化时,成员变量被默认初始化为缺省值。

    class Date{
    public:
    	Date(int year, int month, int day) :
    		_month(month),
    		_day(day) {
    		//函数体内其他操作
    	}
    private:
    	int _year = 1;
    	int _month;
    	int _day;
    };
    
    int main() {
    	//B b();
    	Date d(2024, 1, 31);
    	return 0;
    }
    

    在这里插入图片描述

通常初始化列表与构造函数体内赋值混合使用。


二、explicit关键字

  1. 单参数构造函数可以支持隐式类型的转换。
    意思是允许通过给定类型的单一参数将对象从一种类型转换为另一种类型,而无需显式调用构造函数。

    class Distance {
    private:
        double meters;
    
    public:
        // 单参数构造函数,允许从 double 类型隐式转换为 Distance 类型
        Distance(double m) : meters(m) {}  
    };
    
    int main() {
        // 隐式类型转换:double 到 Distance
        Distance d1 = 10.5;
    
        // 显式类型转换也是可行的
        Distance d2 = Distance(15.2);
        return 0;
    }
    

    在这个例子中,Distance 类具有一个单参数构造函数,允许将 double 类型的值隐式转换为 Distance 类型。当我们使用 Distance d1 = 10.5; 时,编译器会自动调用单参数构造函数,将 10.5 隐式转换为 Distance 类型的对象 d1

  2. C++11及之后的标准中,引入了一种新的特性,即“允许多参数的构造函数用于隐式类型转换”

    例如:

    class MyClass {
    public:
        // 多参数的构造函数
        MyClass(int x, double y) {
            // 构造函数逻辑
            std::cout << "Constructing MyClass with parameters: " << x << ", " << y << std::endl;
        }
    };
    
    int main() {
        // 隐式类型转换,调用构造函数
        MyClass obj = {42, 3.14};
    
        return 0;
    }
    

    在这个例子中,MyClass 类具有一个接受两个参数的构造函数。使用初始化列表 {42, 3.14} 进行对象的初始化时,实际上发生了隐式类型转换,将两个参数传递给构造函数。

  3. 当一个构造函数被 explicit 修饰时,它禁止隐式类型转换,只允许显式调用。

    explicit Distance(double m) : meters(m) {}
    
    // 隐式类型转换会引发编译错误
    Distance d1 = 10.5;  // 错误
    
    // 必须使用显式类型转换
    Distance d2 = Distance(15.2);  // 正确
    

三、static成员

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用
static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化

  1. 静态数据成员: 静态数据成员是属于类而不是类的对象的成员变量。所有类的对象共享相同的静态数据成员。

    class MyClass {
    public:
        // 构造函数,用于增加 count
        MyClass() {
            count++;
        }
        int& GetCount() {
            return count;
        }
    private:
        // 静态数据成员
        static int count;
    };
    
    // 初始化静态数据成员
    int MyClass::count = 0;
    
    int main() {
        // 创建对象,增加 count
        MyClass obj1;
        MyClass obj2;
    
        // 访问静态数据成员
        std::cout << "Count: " << obj1.GetCount() << std::endl;
        std::cout << "Count: " << obj2.GetCount() << std::endl;
    
        return 0;
    }
    
  2. 静态成员函数: 静态成员函数是不依赖于类的实例而存在的函数。它没有访问类的非静态成员,因为它不通过实例来调用,而是通过类名和范围解析运算符 :: 来调用。

    class MathOperations {
    public:
        // 静态成员函数,用于加法运算
        static int add(int a, int b) {
            return a + b;
        }
    };
    
    int main() {
        // 调用静态成员函数
        int result = MathOperations::add(3, 5);
        std::cout << "Result: " << result << std::endl;
    
        return 0;
    }
    

特性总结

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

静态成员函数可以调用非静态成员函数吗?
非静态成员函数可以调用类的静态成员函数吗?

静态成员函数可以调用非静态成员函数,但非静态成员函数不能直接调用类的静态成员函数。这是因为静态成员函数在调用时没有实例上下文,而非静态成员函数必须通过实例来调用。


四、友元

友元(Friend)可以用来解决类的封装性和访问控制方面的一些限制。友元可以是函数、类或者整个类中的函数。友元的存在允许特定的外部实体访问类的私有或受保护成员。

4.1 友元函数

友元函数:使用 friend 关键字声明一个非成员函数,允许该非成员函数访问该类的私有成员。

下面是一个简单的示例:
友元函数的声明通常放在类的声明中,友元函数的定义放在类的外部。

class MyClass {
private:
    int privateData;

public:
    MyClass(int data) : privateData(data) {}

    // 声明友元函数
    friend void displayPrivateData(const MyClass&);
};

// 定义友元函数
void displayPrivateData(const MyClass& obj) {
    std::cout << "Private data: " << obj.privateData << std::endl;
}

int main() {
    MyClass obj(42);
    displayPrivateData(obj); // 友元函数可以访问私有成员
    return 0;
}

displayPrivateData 函数被声明为 MyClass 的友元函数,因此它可以访问 MyClass 中的私有成员 privateData。在 main 函数中,我们可以直接调用 displayPrivateData 函数来显示 obj 对象的私有成员数据。

需要注意的是,友元函数不是类的成员函数,因此它们不能使用成员访问运算符 .-> 来访问私有成员,而是需要通过参数传递对象来访问。


4.2 友元类

友元类:将一个类将另一个类声明为友元,从而允许友元类访问该类的私有成员和受保护成员。

举例:

class MyClass {
private:
    int privateMember;

    // 将 FriendClass 声明为友元类
    friend class FriendClass;

public:
    MyClass(int data) : privateMember(data) {}
};

class FriendClass {
public:
    void accessPrivateMember(const MyClass& obj) {
        // 友元类可以访问 MyClass 的私有成员
        int data = obj.privateMember;
    }
};

int main() {
    MyClass a(10);
    FriendClass b;
    b.accessPrivateMember(a);
    return 0;
}

在这个例子中,FriendClass 被声明为 MyClass 的友元类。因此,FriendClass 的成员函数 accessPrivateMember 可以访问 MyClass 中的私有成员 privateMember

友元类的存在使得特定的类能够共享私有成员,这在某些情况下可能很有用,但同时也可能破坏了封装性。因此,在使用友元类时需要权衡利弊,并确保其使用符合设计原则和需要。


五、内部类

内部类定义在另一个类内部的类,可以直接访问外部类的私有成员,而不需要通过对象来实现。

下面是一个简单的示例:

class Outer {
private:
    int outerPrivate;

public:
    class Inner {
    public:
        void display(const Outer& outer) {
            std::cout << "Inner class accessing outerPrivate: " << outer.outerPrivate << std::endl;
        }
    };

    Outer(int value) : outerPrivate(value) {}

    void callInner() {
        Inner inner;
        inner.display(*this);
    }
};

int main() {
    //通过callInner调用display
    Outer outerObj(42);
    outerObj.callInner();

    //创建inner对象调用display
    Outer::Inner innerObj;
    innerObj.display(outerObj);
    return 0;
}

在这里插入图片描述


六、匿名对象

匿名对象是指在创建对象时不指定对象名的对象。在对象的类型后面直接加上一对括号可以创建匿名对象,而不提供对象名。

匿名对象没有对象名,只能在创建的语句中使用,并且通常在该语句执行结束后就会被销毁。

class MyClass {
public:
    void display() {
        std::cout << "Object is displayed." << std::endl;
    }
};

int main() {
    // 创建匿名对象,并调用其成员函数
    MyClass().display();
    
    return 0;
}

在这里插入图片描述
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

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

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

相关文章

生成树技术华为ICT网络赛道

9.生成树 目录 9.生成树 9.1.生成树技术概述 9.2.STP的基本概念及工作原理 9.3.STP的基础配置 9.4.RSTP对STP的改进 9.5.生成树技术进阶 9.1.生成树技术概述 技术背景&#xff1a;二层交换机网络的冗余性与环路 典型问题1&#xff1a;广播风暴 典型问题2&#xff1a;MA…

OJ_单词个数统计

题干 C实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<map> using namespace std;int main() {//如果输入带空格的字符串&#xff08;scanf不行&#xff09;&#xff1f;eg:This is An Pencil Case//1.fgets()//2.cin.getline();char arr[200]…

PCB经验规则的综合应用

PCB经验规则的综合应用 走线尽量短&#xff0c;长度小于信号波长的十分之一 二是无法短的&#xff0c;就控制它的阻抗 按传输线设计、控制阻抗 首先我们来看看电路板的参数。常见的1.6毫米电路板 1oz 铜箔&#xff0c;介质 FR4&#xff0c;介电常数4.6-4.8&#xff0c;板芯厚…

Redis核心技术与实战【学习笔记】 - 28.Redis 6.0新特性(多线程、客户端缓存与安全)

简述 Redis 6.0 新增了几个关键新特性&#xff0c;分别是面向网络处理的多 IO 线程、客户端缓存、细粒度的权限控制&#xff0c;以及 RESP 3 协议的使用。 其中&#xff0c;面向网络处理的多 IO 线程可以提高网络请求处理的速度&#xff0c;而客户端缓存可以让应用直接在客户…

唐嫣、刘诗诗、杨幂齐聚春晚舞台,再现仙剑三美惊艳绝伦的魅力。

♥ 为方便您进行讨论和分享&#xff0c;同时也为能带给您不一样的参与感。请您在阅读本文之前&#xff0c;点击一下“关注”&#xff0c;非常感谢您的支持&#xff01; 文 |猴哥聊娱乐 编 辑|徐 婷 校 对|侯欢庭 近日&#xff0c;娱乐圈的目光将聚焦于三位璀璨的女星——唐嫣…

opensatck中windows虚拟机CPU核数显示异常问题处理

文章目录 一、问题描述二、元数据信息三、以32核的实例模版为例3.1 单槽位32核3.2 双槽位32核 总结 一、问题描述 openstack创建windows虚拟机的时候&#xff0c;使用普通的实例模版会出现CPU数量和实例模版不一致的问题。需要定制元数据才可以正常显示。 帖子&#xff1a;htt…

七月论文审稿GPT第2.5和第3版:分别微调GPT3.5、Llama2 13B以扩大对GPT4的优势

前言 自去年7月份我带队成立大模型项目团队以来&#xff0c;我司至今已有5个项目组&#xff0c;其中 第一个项目组的AIGC模特生成系统已经上线在七月官网第二项目组的论文审稿GPT则将在今年3 4月份对外上线发布第三项目组的RAG知识库问答第1版则在春节之前已就绪至于第四、第…

python下字符串操作

目录 一&#xff1a;连接字符串 二&#xff1a;字符串切片 三&#xff1a;字符串查找 四&#xff1a;字符串替换 五&#xff1a;字符串大小写转换 六&#xff1a;字符串分割 七&#xff1a;字符串去除空格和特殊字符 八&#xff1a;字符串长度 九&#xff1a;检查字符…

【RT-DETR有效改进】利用SENetV2重构化网络结构 (ILSVRC冠军得主,全网独家首发)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的改进机制是SENetV2,其是2023.11月的最新机制(所以大家想要发论文的可以在上面下点功夫),其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型,而…

ORM模型类

模型 创建两个表 创建模型类 from django.db import models# Create your models here. class BookInfo(models.Model):name models.CharField(max_length10, uniqueTrue) # 书名pub_date models.DateField(nullTrue) # 发布时间read_count models.IntegerField(default…

uniCloud ---- schema2code

目录 schema2code有两种方式 label属性 component属性 group属性 应用 DB Schema里有大量的信息&#xff0c;其实有了这些信息&#xff0c;前端将无需自己开发表单维护界面&#xff0c;uniCloud可以自动生成新增、修改、列表、详情的前端页面&#xff0c;以及admin端的列…

最小生成树超详细介绍

目录 一.最小生成树的介绍 1.最小生成树的简介 2.最小生成树的应用 3.最小生成树的得出方法 二.Kruskal算法 1.基本思想&#xff1a; 2.步骤&#xff1a; 3.实现细节&#xff1a; 4.样例分析&#xff1a; 5.Kruskal算法代码实现&#xff1a; 三.Prim算法 1.基本思想…

如何更改默认浏览器?

打开设置---应用---默认应用 点击你想要设置为默认浏览器的应用&#xff08;假设为Microsoft Edge&#xff09;&#xff0c;点击设置默认值就可以了。

简单实践 spring clound 使用openfeign

1.概要 这是在前面工程基础上的一个变更。 前工程&#xff1a;检查实验 spring cloud nacos nacos-server-2.3.0-CSDN博客 2 代码 2.1 引入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-open…

一般系统的请求认证授权思路【gateway网关+jwt+redis+请求头httpheader】

gateway&#xff1a;网关&#xff0c;我们都知道网关的作用就是对系统的所有请求&#xff0c;网关都会进行拦截&#xff0c;然后做一些操作&#xff08;例如&#xff1a;设置每个请求的请求头httpHeader&#xff0c;身份认证等等&#xff09;此时一般会使用到网关过滤器&#x…

【chromium】vs2022 中 clang构建

vs2022 “D:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\devenv.exe”看起来没装安装 clang 组件 vs2019 装的是12:报错了 Build started... 1>------ Build started: Project: ebBase, Configuration: Debug Win32 ------ 1>d:\Program Files…

【并发编程】手写线程池阻塞队列

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;并发编程 ⛺️稳重求进&#xff0c;晒太阳 示意图 步骤1&#xff1a;自定义任务队列 变量定义 用Deque双端队列来承接任务用ReentrantLock 来做锁并声明两个条件变量 Condition fullWai…

AE2023 After Effects 2023

After Effects 2023是一款非常强大的视频编辑软件&#xff0c;提供了许多新功能和改进&#xff0c;使得视频编辑和合成更加高效和灵活。以下是一些After Effects 2023的特色功能&#xff1a; 新合成预设列表&#xff1a;After Effects 2023彻底修改了预设列表&#xff0c;使其…

《权力的游戏》AI创作大电影 震撼来袭

《权力的游戏》AI创作大电影 震撼来袭 Westeros, a world of power, intrigue, and dark magic. In the frozen North, the army of the dead marches towards Winterfell. The Seven Kingdoms are divided by war and bloodshed, as the Great Houses battle for supremacy.…

必看!嵌入式基于UART的通信协议-RS232、RS485协议解析

这两种都是串口通讯的变种&#xff0c;为了提升串口通信的距离和稳定性。通常来说&#xff0c;正常的串口通信使用的是TTL电平&#xff0c;即高电平为2.4-5V&#xff0c;低电平为0-0.4V。高低电平之间的范围很小&#xff0c;如果有静电或者其他外界的干扰&#xff0c;很快会将低…