首页 > 编程语言 >【c++基础(四)】类和对象下--初始化列表等概念

【c++基础(四)】类和对象下--初始化列表等概念

时间:2024-05-30 19:57:57浏览次数:20  
标签:初始化 -- 成员 c++ month int year day

1.前言

类和对象到这里基本已经接近尾声,本篇文章主要介绍一些与类和对象有关的相关细节,在后续使用类和对象中也有可能用的到。

本章重点:

本篇文章重点讲解初始化列表,友元,匿名对象和类中的static成员,以及类中的内部类的概念。

 2.初始化列表

 在谈论初始化列表之前就要再次提及构造函数了:

在没有初始化列表时,一般我们构建对象都是通过构造函数来进行赋值操作,但是这并不是初始化的操作,这只是赋值的操作,赋值可以多次赋值,而初始化却只能进行一次。

这就引出了初始化列表的概念。

先上例子:

class  Date
{
    public:
    Date(int year, int month, int day)
 : _year(year)
 , _month(month)
 , _day(day) //以上三行就是初始化列表,对象在初始化列表阶段就已经创建好了
 {}
 
private:
 int _year;
 int _month;
 int _day;
};

解释初始化列表的格式:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括 号中的初始值或表达式

初始化列表不仅可以像上面那样使用,也可以在{}里面对初始化的值进行赋值操作

Date(int year, int month, int day)
   : _year(year)
   , _month(month)
   , _day(day)
 {
 	 _year++;
	 _day--;
 }

//或者这样

Date(int year, int month, int day)
   : _year(year)
   , _month(month)
 {
 	 _month = month;
 }

2.1 初始化列表的作用

有些变量在初始化时必须对他赋初值:

例如:

引用成员变量 

const成员变量

自定义类型成员(且该类没有默认构造函数时)

然而在构造函数函数体中的赋值,不叫对变量初始化,用上面的类型会报错
所以此时必须用初始化列表

class B
{
public:
	 B(int a, int ref)
	 :_aobj(a)
	 ,_ref(ref)
	 ,_n(10)
	 {}
private:
	 A _aobj;  // 没有默认构造函数的自定义类型
	 int& _ref;  // 引用成员
	 const int _n; // const修饰成员 
};

因此博主建议:尽量后续在使用类和对象的时候,都用初始化列表进行初始化。

因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。

2.2 初始化列表的小细节

很多小伙伴就问了,是不是初始化列表就是我成员变量初始化的顺序呢?

答案是不是得,成员变量初始化的顺序与初始化列表无关,只与你声明的顺序有关,哪个先声明哪个先进行初始化

上例子:

class A
{
public:
    A(int a)
       :_a1(a)
       ,_a2(_a1)
   {}
private:
    int _a2;
    int _a1;
};
int main() {
    A aa(1);
}

解释:会先声明_a2,再声明_a1

_a2初始化时_a1还是随机值,所以_a2就被初始化成了随机值,而_a1会被初始化为1!

补充对c++11缺省值的理解

成员变量声明时给的缺省值
实际上就是给初始化列表的!

当用户没有显示传参初始化时,编译器会用用户定义的缺省值
当用户显示传参后,缺省值失效,使用用户传的值初始化!

例:

class A
{
public:
    A(int a)//没有显示传参就用缺省值初始化
       :_a1(a)
       ,_a2(a)
   {}
private:
    int _a2 = 1;
    int _a1 = 2;
};
}

3.static成员

概念:

  1. 声明为static的类成员称为类的静态成员

  2. 用static修饰的成员变量
    称之为静态成员变量

  3. 用static修饰的成员函数
    称之为静态成员函数

  4. 静态成员变量一定要在类外进行初始化

static成员的特性

  • 静态成员为所有类对象共享,放在静态区

  • 静态成员变量必须在类外定义,类内只是声明

  • 类静态成员即可用
    类名::静态成员对象.静态成员访问

  • 静态成员函数没有隐藏的this指针
    不能访问任何非静态成员

  • 静态成员受public、protected、private访问限定符的限制

例子:

class B
{
public:
	 static int Add(int x,int y);//没有this指针,无法访问类中成员
	 static int a;//在类中声明
};
int B::a = 10;//在类外定义

此类的所有成员共同享有这个静态变量

【问题】

 

1. 静态成员函数可以调用非静态成员函数吗?不能,因为使用静态成员函数不需要实例化出对象 2. 非静态成员函数可以调用类的静态成员函数吗?可以,静态成员函数他到底也是个函数,可以通过this指针来访问。

4.友元

假设一个函数我想定义在类外
但是我又想访问类中的私有成员
只能将私有成员改为共有再访问

这种操作就破坏了类的封装!

这个时候友元就可以完美的解决这个问题
友元函数可以直接访问类的私有成员
它是定义在类外部的函数,不属于任何类
但需要在类的内部声明
声明时需要加friend关键字
例:
class Date
{
	 friend int Add(int x,int y);//友元函数的声明
public:
	 Date(int year = 1900, int month = 1, int day = 1)
	 : _year(year)
	 , _month(month)
	 , _day(day)
	 {}
private:
	 int _year;
	 int _month;
	 int _day;
};

int Add(int x,int y)//友元函数的定义
{
	x+=_year;
	y+=_month-_day;
	return x+y;
}

对友元函数的几点说明
  • 友元函数可访问类的私有和保护成员
    但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明
    不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数相同

4.1友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。 友元关系是单向的,不具有交换性。 比如上述 Time 类和 Date 类,在 Time 类中声明 Date 类为其友元类,那么可以在 Date 类中直接访问 Time 类的私有成员变量,但想在Time 类中访问 Date 类中私有的成员变量则不行。 友元关系不能传递 如果 B 是 A 的友元, C 是 B 的友元,则不能说明 C 时 A 的友元。 友元关系不能继承,在继承位置再给大家详细介绍。 举例:
class Time
{
 friend class 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)
 {
 // 直接访问时间类私有的成员变量
 _t._hour = hour;
 _t._minute = minute;
 _t._second = second;
 }
 
private:
 int _year;
 int _month;
 int _day;
 Time _t;
};

4.2 内部类

除了有友元函数可以访问类私有成员外
声明友元类也可以达到一样的效果
内部类就是友元类的典型代表!
ps:sizeof(外部类)的大小和内部类无关 上例子:
class A
{
private:
	 static int k;
	 int h;
public:
	 class B // B天生就是A的友元
	 {
	 public:
		 void foo(const A& a)
		 {
			 cout << k << endl;//OK
			 cout << a.h << endl;//OK
		 }
	 };
};

5.类的匿名对象

先定义一个类

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

使用匿名对象:

Date d = Date(2023,8,1);

这里的:Date(2023,8,1)就是匿名对象

特性:
  • 生命周期只有一行
  • 没有名字,在初始化或销毁时
    自动调用构造或析构函数
匿名对象使用场景: 当定义一个变量只是为了调用类中的一个函数,并且调用完后,此变量不会再被使用,此时可用匿名对象

6.explicit关键字

构造函数不仅能构造和初始化对象,对于单个参数或除第一个参数无默认值
其余均有默认值的构造函数,还有隐式类型转换的作用
概念听起来好像有点迷魂,话不多说直接上例子
class Date
{
public:
 Date(int year)
	 : _year(year)
	 {}
private:
	 int _year;
	 int _month = 1;
	 int _day = 1;
};

int main()
{
	Date d = 1999;
	return 0;
}

这里的Date d=1999就会有隐式类型转换

但是如果你加了explicit之后,就把隐式类型转换封住了,就不能使用了。那么就会报错。

只需要在构造函数前面+explicit即可,例

explicit Date(int year)
	 : _year(year)
	 {}

到这本文就结束了!

                                               下期预告:c++内存管理

标签:初始化,--,成员,c++,month,int,year,day
From: https://blog.csdn.net/weixin_62196764/article/details/139296150

相关文章

  • [JSOI2015] 染色问题
    [JSOI2015]染色问题题目描述萌萌家有一个棋盘,这个棋盘是一个\(n\timesm\)的矩形,分成\(n\)行\(m\)列共\(n\timesm\)个小方格。现在萌萌和南南有\(C\)种不同颜色的颜料,他们希望把棋盘用这些颜料染色,并满足以下规定:棋盘的每一个小方格既可以染色(染成\(C\)种颜......
  • uoj项目部署的学习实践和基于JUnit进行的项目测试
    基于JUnit进行的项目测试对不同功能点进行测试:检测忘记密码功能、注册功能能否正常使用脚本文件:registerTest.java1.检测忘记密码功能。事先注册好一个账号用于测试测试步骤:输入账号输入电子邮箱输入验证码1)用例标题:验证码错误情况测试数据:账号2021127电子邮箱2848250......
  • uoj概述
    一、基本工作原理UOJ主要由两部分组成:网页端和测评端。顾名思义,网页端就是用来通过网页与用户交互的,测评端则是在用户发出测评请求时负责测评并将结果发送给网页端的。网页端什么是网页端?顾名思义,就是管网页的部分。网页端又分为网页前端和网页后端。所谓网页前端,就是你打开浏......
  • 答案检查器
    五.答案检查器本文将引导您写一个自定义的checker(chk.cpp)。按照套路,uoj的校验器也应该使用testlib编写。下面是A+BProblem的校验器:#include"testlib.h"intmain(intargc,char*argv[]){registerTestlibCmd(argc,argv);intpans,jans;pans=ouf.readInt();//......
  • 数据检验器
    四.数据检验器uoj的数据检验器(val.cpp)使用testlib。下面是A+BProblem的检验器:#include"testlib.h"usingnamespacestd;intmain(void){registerValidation();inf.readInt(0,1000000000,"A");inf.readSpace();inf.readInt(0,1000000000,"B");in......
  • 特殊需求的配置
    三.特殊需求配置由于很多题目有乱七八糟的配置,uoj用了一些不清真的方法来实现。1.子任务子任务模式中,必须把某个subtest的数据全部通过才能拿到对应的分数。在problem.conf中,可以设置每个子任务在哪个测试点结束,并给每个子任务分配对应的分数。它的写法如下:[n_tests40.........
  • 传统题的配置
    二.传统题配置1.数据对于传统题,上传的×.zip数据包应当包括这些内容:题目配置文件测试数据额外测试数据(包括题面中所给的测试样例)(开启hack)数据检验器(开启hack)标准程序2.题目配置文件题目配置文件应当命名为problem.conf。这是一份配置的样例:[n_tests10n_ex_tests1n......
  • uoj项目部署中题目管理的相关学习与应用
    一.概述1.新建题目和管理界面只有超级管理员有权限新建题目,每次新建题目都必须由超级管理员完成。在题目页面,超级管理员或该题目的管理员可以通过管理按钮进入题目管理界面。题目管理界面分为三个选项卡:编辑:题面编辑页面管理者:题目管理员管理页面数据:题目数据管理页面以及......
  • 基于JUnit进行的项目测试
    基于JUnit进行的项目测试对不同功能点进行测试:检测忘记密码功能、注册功能能否正常使用脚本文件:registerTest.java1.检测忘记密码功能。事先注册好一个账号用于测试测试步骤:输入账号输入电子邮箱输入验证码1)用例标题:验证码错误情况测试数据:账号2021127电子邮箱2848250......
  • DeerOJ的前端框架介绍-model文件夹
    model文件夹model文件夹下存储的是一些相关类的php文件,在HTML文件生成的时候,利用这些类能够高效地辅助文件与文件之间的调度转换。文件夹下的内容如下:这里列举一些重要的类文件:Route.php文件前文中在实现route.php的路由调度过程中有出现使用类Route的情况,实际上就是调用这......