一:构造函数函数初始化列表初始化:
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
类中包含以下成员,必须放在初始化列表位置进行初始化:
- 引用成员变量
- const成员变量
- 自定义类型成员(该类没有默认构造函数) 默认构造函数就是不用传参可以调用的构造函数有三个: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指针,不能访问非静态成员。
- 静态成员为所有类对象所共享,不属于某个具体的实例,它在静态区
- 静态成员变量必须在类外定义,定义时不添加static关键字
- 类静态成员即可用类名::静态成员或者对象.静态成员来访问 就是A()::GetN()、a1.GetN()、A::GetN()
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员和类的普通成员一样,也有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;
};