当前位置: 首页 > article >正文

初始化列表、静态成员、友元

一:构造函数函数初始化列表初始化:
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
类中包含以下成员,必须放在初始化列表位置进行初始化:

  1. 引用成员变量
  2. const成员变量
  3. 自定义类型成员(该类没有默认构造函数) 默认构造函数就是不用传参可以调用的构造函数有三个:1.全缺省 2.无参的 3.编译器自动生成的
class A
{
public:
	A(int x = 0) // 默认构造函数 定义Date d的时候可以调动
		_x = x;
	A(int x)  // 不是默认构造函数 定义Date d的时候调不动,得配合在Date类的初始化的初始化列表调用才可以调得动
		_x = x;
private:
	int _x;
}
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		,_month(month)
		,_day(day)
		,_n(10)
		,_tmp(year)
		,_a(1) //如果A中没有默认构造函数就需要这样子做
	{}
private:
	// 不是成员变量的定义,仅仅是成员变量的声名
	// 这些成员都属于对象,在main中对象被定义出来后才算定义了成员变量
    int _year;
    int _month;
    int _day;

	int& _tmp; //引用必须在定义的时候(初始化列表)初始化 (const也得在定义的时候初始化)
	const int _n; //必须在初始化列表初始化,不能在函数体内初始化
	A _a; //自定义类型定义的时候自动调用它的构造函数
};

成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
下述代码private中先定义的_a2,因此初始化先初始化a2,再初始化_a1,所以选D。1 随机值

class A
{
public:
	A(int a)
		:_a1(a)
		,_a2(_a1)
	{}
	void Print() {
		cout<<_a1<<" "<<_a2<<endl;
	}
private:
	int _a2;
	int _a1;
}
int main() {
	A aa(1);
	aa.Print();
}

单参数的构造函数支持隐式类型转换。

class A
{
public:
	A(int a)
		:_a(a)
	{}
private:
	int _a;
};
class B
{
public:
	explicit A(int b) //加上这个关键字不支持类型转换
		:_b(b)
	{}
private:
	int _b;
};
int main()
{	
	int i = 0;
	double j = i; // 隐式类型转换
	A a1 = 2; // 将int类型2转换为 A 类型 调用构造函数构造
	B b1 = 2; // 不能编译过去
	A(2); // 构造匿名对象 生命周期只在这一行
}

二:静态成员:
实现一个类,计算中程序中创建出了多少个类对象。
在类中定义静态成员,然后在构造和拷贝构造函数中对静态成员变量进行++,每调用一次就会自己++一次。类中的静态成员变量是声名,不在构造函数初始化,需要在类外进行初始化定义。
静态成员函数和普通的成员函数区别:没有this指针,不能访问非静态成员。

  1. 静态成员为所有类对象所共享,不属于某个具体的实例,它在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字
  3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问 就是A()::GetN()、a1.GetN()、A::GetN()
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

静态成员函数可以调用非静态成员函数吗?不可以 在GetN中不能调用f,因为GetN没有this指针
非静态成员函数可以调用类的静态成员函数吗?可以,f可以调用GetN。

class A
{
public:
	A()
	{
		_n++;
	}
	A(const A& a)
	{
		_n++;
	}
	//int GetN()
	//{
	//	return _n;
	//}
	void f()
	{}
	// 静态成员函数和普通的成员函数区别:没有this指针,不能访问非静态成员。
	static int GetN()
	{}
private:
	// 声名 不在构造函数初始化
	static int _n; // 存在静态区 属于整个类 属于类的所有对象 生命周期是全局的
};
int A::_n = 0; // 在这里初始化 第一次可以初始化
int main()
{
	A a;
	cout << sizeof(A) << endl; // 1
	cout << sizeof(a) << endl; // 1
	cout << a.GetN() << endl; // 可以知道创建了多少次对象
	return 0;
}

题目:求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。数据范围: 0<n≤200 进阶: 空间复杂度 O(1),时间复杂度 O(n)
解:创建一个Add类,n是多少就创建大小为n的Add类型的数组,这样在Add的构造函数定义++,对static类型的数据进行++,就可以完成求和。Init函数是为了防止在oj题目中多接口去测试而导致_i和_ret没有在下次调用初始化的问题。

class Add{
public:
    Add(){
        _ret += _i;
        _i++;
    }
    static int Get(){
        return _ret;
    }
    static void Init(){
        _i = 1;
        _ret = 0;
    }
private:
    static int _i;
    static int _ret;
};
int Add::_i = 1;
int Add::_ret = 0;
class Solution {
public:
    int Sum_Solution(int n) {
        Add::Init();
        Add arr[n]; //变长数组
        return Add::Get();
    }
};

题目:根据输入的日期,计算是这一年的第几天。保证年份为4位数且日期合法。
进阶:时间复杂度:O(n),空间复杂度:O(1)
输入描述:
输入一行,每行空格分割,分别是年,月,日
输出描述:
输出是这一年的第几天
eg:
输入:2012 12 31
输出:366

#include <iostream>
using namespace std;
int GetDay(int year, int month){
    int dayArray[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    int day = dayArray[month];
    // 每四年一润但百年不润 但是四百年润
    if (month == 2 &&((year % 4 == 0 && year % 100 != 0) || (year%400 == 0)))
    {
        day += 1;
    }
    return day;
}
int main() {
    int _year = 0;
    int _month = 0;
    int _day = 0;
    int ret = 0;
    cin >> _year >> _month >> _day;
    while(_month > 0)
    {
        _month--;
        ret += GetDay(_year, _month);
    }
    cout <<(ret + _day) << endl;
}

cout是ostream类型的对象
cin是istream类型的对象
友元函数:破坏封装的行为。
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
友元函数可访问类的私有和保护成员,但不是类的成员函数
友元函数不能用const修饰 // const是修饰this指针的,友元函数不属于类函数。
友元函数可以在类定义的任何地方声明,不受类访问限定符限制,可以定义在类中任何位置
一个函数可以是多个类的友元函数
友元函数的调用与普通函数的调用和原理相同

class Date
{
	//友元函数的声名 加一个友元的函数声明。
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year, int month, int day)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	
	// cout << d1; cout就变成左操作数,就把cout给this了。
	ostream& operator<<(ostream& _cout) // ostream& operator<<(Date* this, ostream& _cout)
	{
		_cout<<d._year<<"-"<<d._month<<"-"<<d._day;
		return _cout;
	}
prvate:
	int _year;
	int _month;
	int _day
};

// 友元函数
ostream& operator<<(ostream& _cout, const Date& d) // ostream&的返回值可以支持连续输出
{
	_cout<<d._year<<"-"<<d._month<<"-"<<d._day;
	return _cout;
}
istream& operator>>(istream& _cin, Date& d) // 输入需要修改不加const
{
	_cin>>d._year>>"-">>d._month<<"-">>d._day;
	return _cin;
}
int main()
{
	Date d(2017, 12, 24);
	// cout<<d; // cout就变成左操作数,就把cout给this了,
	d<<cout; // 这个可以调用成员内函数打印 但写法不太相同 因此直接写成员函数不是很方便 
	cout << d; // 依靠友元通过类外函数访问成员内变量并打印
	Date d1(2017, 12, 24); // ostream&的返回值可以支持连续输出
	Date d2(2017, 12, 24);
	cout << d1 << d2; // 从左到右结合 cout<<d1返回一个cout
	return 0;
}

友元类: A是B的友元(在B中写friend class A;),A中可以访问B,B不能访问A。
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
友元关系是单向的,不具有交换性。比如Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
友元关系不能传递,如果B是A的友元,C是B的友元,则不能说明C时A的友元。

class Date;   
// 前置声明
class Time
{
	friend class Date;  // Date要访问time的内容,把Date定义成time的友元类
	// 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
	public:
	Time(int hour, int minute, int second)
		: _hour(hour)
		, _minute(minute)
		, _second(second)
	{}
private:
	int _hour;
	int _minute;
	int _second;
};
class Date // Date要访问time的内容,把Date定义成time的友元类
{
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;
};

http://www.kler.cn/news/353688.html

相关文章:

  • Nacos2.3.2在ubuntu中的部署
  • R语言绘图——坐标轴及图例
  • (41)MATLAB中fftshift函数与ifftshift函数的用法
  • 程序设计说明书
  • 10.17学习
  • C语言双向链表操作
  • I\O进程线程(Day29)
  • leetcode力扣刷题系列——【最小元素和最大元素的最小平均值】
  • uniapp vue3 watch监听使用情况
  • 【微服务】深入探讨微服务架构:现代软件开发的变革之路
  • 【Postgresql】根据响应数据反向实现建表语句与insert语句
  • C++11 wrapper装饰器 bind+function
  • 【服务器知识】Tomcat简单入门
  • 10月17日,每日信息差
  • Leetcode 最小栈
  • 小白投资理财 - 中国股票代号
  • NVIDIA Bluefield DPU上的启动流程4个阶段分别是什么?作用是什么?
  • 机器学习——主要分类
  • 2024软件测试面试大全(答案+文档)
  • Springboot 整合 Java DL4J 实现安防监控系统