首页 > 编程语言 >【C++】初始化列表、隐式转换、static成员、友元与匿名对象

【C++】初始化列表、隐式转换、static成员、友元与匿名对象

时间:2024-05-30 21:58:53浏览次数:27  
标签:友元 初始化 函数 int 成员 C++ static Date

文章目录

在这里插入图片描述

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. 类中包含以下成员,必须放在初始化列表位置进行初始化:
    • const成员变量
    • 引用成员变量
    • 没有默认构造的自定义类型成员

在这里插入图片描述

在这里插入图片描述

  1. 初始化列表不管你写不写,每个成员变量都会走一遍
    • 自定义类型会调用其默认构造(没有默认构造就报错)
    • 内置类型有缺省值,就用缺省值;没有缺省值,要看编译器是否会处理
    • 会先走初始化列表,再走函数体
    • 实践中,尽可能得使用初始化列表初始化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

在这里插入图片描述
将类中成员a1与a2换个位置就会得到想要的结果:1,1。

  1. 缺省值与初始化列表

我们都知道,在C++11中允许给内置成员一个缺省值。那么这个缺省值是给谁使用的呢?-----初始化列表
在这里插入图片描述

2.explicit关键字

2.1隐式类型转换

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

  1. 单参构造的隐式转换

什么意思呢?看下面的代码

class A
{
public:
	A(int a)
		:_a(a)
	{

	}
private:
	int _a;
};

int main()
{
	A a1(1);
	//拷贝构造
	A a2 = a1;

	//下面这样写为什么可以呢?
	A a3 = 2;
	return 0;
}

为什么可以用一个内置类型给一个自定义类型的变量呢?
存在隐式类型转换

在这里插入图片描述

在内置类型转换之间以会产生一个临时变量,而且该临时变量具有常性,必须使用const修饰。
在这里插入图片描述

对于自定义类型而言,也是这样的,若想引用常量,必须加const.
在这里插入图片描述

在发生构造和拷贝构造的过程中,编译器会存在优化

在这里插入图片描述
为什么能这样隐式转换呢?什么支持的?

单参数构造函数支持的
在这里插入图片描述

  1. 多参构造的隐式转换

多参构造是如何调用的呢?
跟单参构造的调用过程一致。但写法不同,多参构造需要写花括号

class A
{
public:
	//多参构造
	A(int a, int b, int c)
		:_a(a)
		,_b(b)
		,_c(c)
	{

	}
		
private:
	int _a;
	int _b;
	int _c;
};

class Stack
{
public:
	void Push(const A& a)
	{
		//....
	}
};

int main()
{	
	//如何构造
	A a1(1, 2, 3);
	A a2 = { 1,2,3 };
	const A& a3 = { 4,5,6 };

	//注意这里的写法
	Stack st;
	st.Push(a1);
	st.Push({ 1,2,3 });
	return 0;
}

2.2explicit

如果不想让隐式转换发生,可以加explicit关键字。

在这里插入图片描述

3.static成员

3.1成员变量

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;
用static修饰的成员函数,称之为静态成员函数。
在这里插入图片描述

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

在这里插入图片描述

那么这个static修饰成员变量有什么用呢?

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

在这里插入图片描述

3.2成员函数

当静态成员变量是私有时,我们该如何访问呢?

在这里插入图片描述

通过静态成员函数访问

在这里插入图片描述

特征:

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

4.友元

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数和友元类

4.1友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字

class Date
{
	//友元函数声明
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
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;
}

注意:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰,因为它没有this指针
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数
  • 友元函数的调用与普通函数的调用原理相同

4.2友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

  • 友元关系是单向的,不具有交换性。
    比如下面的Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  • 友元关系不能传递
    如果C是B的友元, B是A的友元,则不能说明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)
        
    {}
private:
    int _year;
    int _month;
    int _day;
    void SetTimeOfDate(int hour, int minute, int second)
    {
        // 直接访问时间类私有的成员变量
        _t._hour = hour;
        _t._minute = minute;
        _t._second = second;
    }
    Time _t;
};

5.内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

class A
{
private:
	static int _s;
	int _a;

public:
	
	//内部类
	class B
	{
	public:

	private:
		int _b;
	};
};
int A::_s = 1;
int main()
{
	return 0;
}
  1. 内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。

在这里插入图片描述
A类中没有一个B类的成员,它们两个就是一个平行的类,各自独立。
将B放在A里面,仅仅是受到类域的限制

在这里插入图片描述

  1. 内部类可以定义在外部类的public、protected、private都是可以的

如果将内部类设置为私有,那么就只有外部类中可以使用,其它地方均不可以使用。

在这里插入图片描述

在这里插入图片描述

  1. 内部类天生就是外部类的友元类

内部类可以通过外部类的对象参数来访问外部类中的所有成员,但是外部类不是内部类的友元。

在这里插入图片描述

6.匿名对象

很简单,匿名对象就是没有名字的对象,匿名对象的特点不用取名字,直接用类名

它的生命周期仅在当前行(现用完,现析构)

在这里插入图片描述

标签:友元,初始化,函数,int,成员,C++,static,Date
From: https://blog.csdn.net/weixin_69380220/article/details/139298359

相关文章

  • 校园导航系统C++
    制作一个简单的大学城导航系统,根据用户指定的起点和终点,求出最短路径长度以及具体路径。项目要求:1)程序与数据相分离,地图中的所有数据都是从文件读入,而不是写在代码中2)最短路径算法不能调用函数库3)菜单界面可以循环显示,每次显示前先清屏4)输入的起点和终点若不存在,能给出相......
  • Linux C进阶 —— 与C++互相调用
      本文介绍C、C++函数互相引用的方法,以及各类目标文件(含.o目标文件、.a静态库、.so动态库)在互调使用中的详细编译链接方法。本文使用arm的交叉编译工具链作为编译和链接工具。1.C调用C++方法(asio为c++库)示例源码树:$tree..├──include│├──asio││├──......
  • c++结构体解决复数辐角问题
     结构体相关知识及运行代码(来自发发老师)/*ch10_structs.cc介绍:这里解释了结构体的使用方法。包括:(1)定义和初始化。(2)赋值。(3)结构体和数组一起使用。注意数据成员和函数成员的访问。(4)结构体和向量一起使用。(5)结构体和函数。*/#include<iostream>......
  • 【c++基础(五)】内存管理--new
    1.前言在C语言中,有四个内存管理函数:malloc,calloc,realloc和free但是使用起来他们却是非常的不方便:int*p1=(int*)malloc(sizeof(int)*n);int*p2=(int*)calloc(4,sizeof(int));int*p3=(int*)realloc(p2,sizeof(int)*10);同时这里也会出现一个问题,malloc不会进......
  • 【c++基础(四)】类和对象下--初始化列表等概念
    1.前言类和对象到这里基本已经接近尾声,本篇文章主要介绍一些与类和对象有关的相关细节,在后续使用类和对象中也有可能用的到。本章重点:本篇文章重点讲解初始化列表,友元,匿名对象和类中的static成员,以及类中的内部类的概念。 2.初始化列表 在谈论初始化列表之前就要再次......
  • 区间和(C++)
    题目描述】给定一个全部为零的数列,规定有两种操作,一是修改某个元素,二是求区间的连续和。【输入】输入数据第一行包含两个正整数n,m(n≤100000,m≤500000) ,以下是m 行,每行有三个正整数k,a,b (k=0 或1,a,b≤n ).k=0 时表示将a 处数字加上b ,k=1 时表示询问区间[a,b......
  • 一文搞懂C++继承、多继承、菱形继承、虚继承
    继承目录继承继承继承的访问权限子类赋值给父类赋值兼容规则“天然”的行为验证:1.其他权限继承能否支持赋值兼容规则2.是否"天然",有没有产生临时变量继承中的作用域继承的构造函数继承的拷贝构造继承的operator=继承的析构函数析构顺序析构的特殊处理继承中的static成员设计一......
  • C++结构体使用
    文章目录原文链接一、结构体基本概念二、使用及定义三、结构体数组四、结构体指针六、结构体做函数参数值传递和地址传递的区别七、结构体中const的使用场景原文链接c++中的结构体一、结构体基本概念结构体属于用户自定义的数据类型,允许用户存储不同的数据类型......
  • c++ 模板 元编程
    模板是门新语言C++元编程是一种使用模板元编程技术实现的编程方式,它允许程序员在编译期进行计算和代码生成。相比于传统的运行时编程,C++元编程可以提高程序的执行效率,减少资源开销,使得编译器能够优化代码,从而在一些对性能要求较高的场景中有着广泛的应用。   来自:https:/......
  • C++ Primer Plus(第6版):程序的创建过程
    一个C++程序是如何一步步创建的呢?一般来说主要分为三个过程:使用文本编辑器编写程序,并将其保存至文件中,这个文件就是程序的源代码。编译源代码。这是指将源代码翻译为主机使用的内部语言--机器语言,将翻译后的代码称之为目标代码(objectcode)。将目标代码与其它代码链接起来。链......