目录
再谈构造函数
构造函数体赋值
在之前我们讲构造函数是这样初始化的:
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
那到底怎样在构造函数体内表示才算初始化呢?--->
初始化列表
举个栗子:
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
只能在初始化列表初始化的成员及注意事项
举个栗子:
class A
{
public:
A(int a) //不传参不能调用该构造函数,不是默认构造函数
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int ref)
:_a(a)
, _ref(ref)
, _n(10)
{}
private:
A _a; // 没有默认构造函数
int& _ref; // 引用
const int _n; // const
};
3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
我们来演示一下:
4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
我们来通过一个场景演示一下:
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();
}
explicit
举个栗子:
class Date
{
public:
Date(int year)
:_year(year)
{}
private:
int _year;
int _month;
int _day;
};
void TestDate()
{
Date d1(2018);
// 用一个整形变量给日期类型对象赋值
// 实际编译器背后会用2019构造一个临时对象,最后用临时对象给d1对象进行赋值
d1 = 2019;
}
static成员
概念
面试题:实现一个类,计算中程序中创建出了多少个类对象。
class A
{
public:
A()
{
++_count;
}
A(const A& t)
{
++_count;
}
static int GetACount()
{
return _count;
}
private:
static int _count;
};
int A::_count = 0; //静态成员变量初始化,需要指定类域
void TestA()
{
cout << A::GetACount() << endl; //调用类里面静态成员函数方法之一
A a1;
A a2;
A a3(a1);
cout << A::GetACount() << endl;
}
int main()
{
TestA();
return 0;
}
运行结果:
特性
【问题】
1. 静态成员函数可以调用非静态成员函数吗? 不可以
举个栗子:
class Date
{
Date(int year =1,int month =1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
void Print()
{
cout << _year << " " << _month << " " << _day << endl;
}
static int CountDate()
{
Print();
_count++;
}
private:
int _year;
int _month;
int _day;
static int _count;
};
int Date::_count = 0;
int main()
{
return 0;
}
运行如下:
2. 非静态成员函数可以调用类的静态成员函数吗? 可以
举个栗子:
class Date
{
public:
Date(int year =1,int month =1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
void Print()
{
HelloPrint();
cout << _year << " " << _month << " " << _day << endl;
}
static void HelloPrint()
{
cout << "hello world" << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
return 0;
}
运行结果:
3. 静态成员函数可以调用非静态成员变量吗? 不可以
举个栗子:
class Date
{
public:
Date(int year =1,int month =1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
static void Print()
{
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
d.Print();
return 0;
}
运行如下:
4. 非静态成员函数可以调用类的静态成员变量吗? 可以
举个栗子:
class Date
{
public:
Date(int year =1,int month =1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
void Print()
{
cout << _count << endl;
cout << _year << " " << _month << " " << _day << endl;
}
private:
int _year;
int _month;
int _day;
static int _count;
};
int Date::_count = 0;
int main()
{
Date d;
d.Print();
return 0;
}
运行结果:
总结
C++11 的成员初始化新玩法
举个栗子:
class Date
{
public:
void Print()
{
cout << _year << " " << _month << " " << _day;
}
private:
//非静态成员变量,可以在成员声明时给缺省值
int _year = 2022;
int _month = 3;
int _day = 3;
};
int main()
{
Date d;
d.Print();
return 0;
}
我们来打印输出一下,看看我们给的缺省值是否给成员变量初始化了:
如果我们写了拷贝构造(这时候必须写构造函数,具体原因之前讲述过了~),但是又想使用编译器默认生成的构造函数就可以这样来定义:
Date() = default;
友元
友元函数
上面一大段话是什么意思呢?我们用代码演示一下就能明白了:
看下面代码:
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
, _day(day)
{}
ostream& operator<<(ostream& _cout)
{
_cout << _year << "-" << _month << "-" << _day;
return _cout;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d(2022, 3, 3);
//cout << d; 正常思维逻辑
d << cout; //然而定义到类内部只能这样使用
return 0;
}
但是我们直接定义到类外面就不能访问类里面的私有成员了,但是也不能把私有成员改成公有,这样会破坏原来的封装性。这时候友元函数就派上用场了:
class Date
{
friend ostream& operator<<(ostream& _cout,const Date& d);
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& _cout,const Date& d)//没有了this指针抢位的问题
{
_cout << d._year << "-" <<d. _month << "-" << d._day;
return _cout; //这样支持连续输出_cin也是类似
}
int main()
{
Date d(2022, 3, 3);
//cout << d; 正常思维逻辑
cout << d; //然而定义到类内部只能这样使用
return 0;
}
运行结果:
注意:
友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
友元函数的相关说明:
友元类
1、友元关系是单向的,不具有交换性。
举个栗子:
class Date
{
friend class Time;//Time是Date的友元类,可以访问Date里面的私有成员变量
public:
Date(int year = 2022, int month = 3, int day = 3)
: _year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
class Time
{
public:
void Print(const Date& d)
{
cout << d._year << " " << d._month << " " << d._day;
cout << endl;
_d._year = 1;
_d._month = 1;
_d._day = 1;
cout << _d._year << " " << _d._month << " " << _d._day; //这种写法不用传参
}
private:
int _hour;
int _minute;
int _second;
Date _d;
};
int main()
{
Date d;
Time t;
t.Print(d);
return 0;
}
运行结果:
2、友元关系不能传递
举个栗子:
class Time
{
private:
int _hour = 12;
int _minute = 12;
int _second = 12;
}; //为了能够保证Dtae调用到Time,需要Time定义到Date前面,或者声明一下
class Date
{
friend class Time;
public:
void Print(const Time& t)
{
cout << t._hour << ":" << t._minute << ":" << t._second << endl;
}
};
int main()
{
Date d;
Time t;
d.Print(t);
return 0;
}
我们运行一下上面的代码看是否能过:
内部类
概念及特性
sizeof(外部类)=外部类,和内部类没有任何关系。
class Date
{
public:
Date(int year = 2022, int month = 3, int day = 3)
: _year(year)
, _month(month)
, _day(day)
{}
class Time
{
public:
void Print(const Date& d)
{
cout << d._year << " " << d._month << " " << d._day;
}
private:
int _hour;
int _minute;
int _second;
};
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d;
cout << sizeof(d) << endl;
Date::Time t;
cout << sizeof(t) << endl;
return 0;
}
运行结果如下:
牛客网一道练习题
求1+2+3+...+n_牛客题霸_牛客网
代码:
class Sum
{
public:
Sum()
{
_ret += _i;
_i++;
}
static int GetN()
{
return _ret;
}
static void Init()
{
_i = 1;
_ret = 0;
}
private:
static int _i;
static int _ret;
};
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution {
public:
int Sum_Solution(int n)
{
Sum::Init();
Sum arr[n];//Sum* p = new Sum[n];
return Sum::GetN();
}
};
我们不用静态成员时:
再次理解封装
下面举个例子来让大家更好的理解封装性带来的好处,比如:乘火车出行
我们来看下火车站:
售票系统:负责售票----用户凭票进入,对号入座
工作人员:售票、咨询、安检、保全、卫生等
火车:带用户到目的地
想想下,如果是没有任何管理的开放性站台呢?火车站没有围墙,站内火车管理调度也是随意,乘车也没有规矩,比如: