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

一:构造函数函数初始化列表初始化:

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

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

每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

类中包含以下成员,必须放在初始化列表位置进行初始化:

  1. 引用成员变量
  2. const成员变量
  3. 自定义类型成员(该类没有默认构造函数) 默认构造函数就是不用传参可以调用的构造函数有三个:1.全缺省 2.无参的 3.编译器自动生成的
cpp 复制代码
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 随机值

cpp 复制代码
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();
}

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

cpp 复制代码
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。

cpp 复制代码
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没有在下次调用初始化的问题。

cpp 复制代码
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

cpp 复制代码
#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指针的,友元函数不属于类函数。

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

一个函数可以是多个类的友元函数

友元函数的调用与普通函数的调用和原理相同

cpp 复制代码
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的友元。

cpp 复制代码
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;
};
相关推荐
Dontla18 分钟前
Rust泛型系统类型推导原理(Rust类型推导、泛型类型推导、泛型推导)为什么在某些情况必须手动添加泛型特征约束?(泛型trait约束)
开发语言·算法·rust
Ttang2324 分钟前
Leetcode:118. 杨辉三角——Java数学法求解
算法·leetcode
喜欢打篮球的普通人25 分钟前
rust模式和匹配
java·算法·rust
java小吕布39 分钟前
Java中的排序算法:探索与比较
java·后端·算法·排序算法
tumu_C1 小时前
C++模板特化实战:在使用开源库boost::geometry::index::rtree时,用特化来让其支持自己的数据类型
c++·开源
杜若南星1 小时前
保研考研机试攻略(满分篇):第二章——满分之路上(1)
数据结构·c++·经验分享·笔记·考研·算法·贪心算法
路遇晚风1 小时前
力扣=Mysql-3322- 英超积分榜排名 III(中等)
mysql·算法·leetcode·职场和发展
Neophyte06081 小时前
C++算法练习-day40——617.合并二叉树
开发语言·c++·算法
木向1 小时前
leetcode104:二叉树的最大深度
算法·leetcode