1. 构造函数(扩充)
(1)构造函数体赋值
- 在创建对象时,编译器通过调用构造函数,给对象中的各个成员变量一个合适的初始值。
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
(2)初始化列表
- 初始化列表:以冒号开始,接着是以逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式。
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)
{}
private:
int _year;
int _month;
int _day;
};
- 初始化只能初始化一次,而构造函数体内可以多次赋值。
- 类中包含引用成员变量、const成员变量、自定义成员变量,必须放在初始化列表位置进行初始化。
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int ref)
:_aobj(a)
,_ref(ref)
,_n(10)
{}
private:
int _aobj;
int& _ref;
const int _n;
};
- 对于自定义类型成员变量,会先使用初始化列表初始化。
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
class A
{
public:
A(int a)
:_a1(a)
, _a2(_a1)
{}
void display()
{
cout << _a1 << " " << _a2 << endl;
}
private:
int _a2;
int _a1;
};
void test()
{
A aa(1);
aa.display();
}
(3)explicit关键字
- 构造函数不仅可以构造与初始化函数,对于单个参数的构造函数,还具有类型转换的作用。
- 用explicit修饰构造函数,将会禁止单参构造函数的隐式转换。
class Date {
public:
Date(int year)
:_year(year)
{}
explicit Date(int year)
:_year(year)
{}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1(2021);
}
2. static
- 声明为static的类成员称为静态成员,用static修饰的成员变量称为静态成员变量,用static修饰的成员函数称为静态成员函数。
- 静态的成员变量一定要在类外进行初始化。
特性 - 静态成员为所有类对象共享,不属于某个具体的实例;
- 静态成员必须在类外定义,定义时不添加static关键字;
- 类静态成员可以用 类名::静态成员或者对象.静态成员来访问;
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员;
- 静态成员和类的普通成员一样,也有三种访问级别:public、private、protected。也可以具有返回值。
class A {
public:
A()
{
++_count;
}
A(const A&())
{
++_count;
}
static int getcount()
{
return _count;
}
void fun()
{
this->getcount();
cout << "fun" << endl;
}
static int _count;
};
int A::_count = 0;
A funA(A a)
{
return a;
}
void test()
{
cout << A::_count << endl;
cout << A::getcount() << endl;
A a1;
A a2;
A a3 = funA(a1);
cout << a1.getcount() << endl;
cout << a2.getcount() << endl;
cout << a3.getcount() << endl;
cout << A::getcount() << endl;
cout << a1._count << endl;
cout << A::_count << endl;
}
- 静态成员函数不可以调用非静态成员函数;
- 非静态成员函数可以调用类的静态成员函数。
3.友元
- 提供了一种突破封装的方式,但会增加耦合度,破坏了封装,不宜多用。
友元函数
- 友元函数可以直接访问类的私有成员,它是定义在类外的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加上friend关键字。
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){}
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 >> d._month >> d._day;
return _cin;
}
void test()
{
Date d(2021, 3, 8);
cout << d;
operator<<(cout, d);
cout << d << endl;
operator<<(cout, d) << endl;
Date d1(2021, 3, 8);
cin >> d1 >> d1 >> d1;
}
友元类
- 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有函数。
- 友元关系是单向的,不具有交换性;
- 友元关系不能传递
class Time
{
friend class Date;
public:
Time(int hour = 1, int minute = 1, int second = 1);
void fun(Date& d);
private:
int _hour;
int _minute;
int _second;
};
#include"time.h"
class Date
{
friend class Time;
public:
Date(int year = 1900, int month = 1, int day = 1);
void SetTimeOfDate(int hour, int minute, int second);
private:
int _year;
int _month;
int _day;
Time _t;
};
#include"test.h"
class Date;
Time::Time(int hour, int minute, int second) :_hour(hour), _minute(minute), _second(second)
{
}
void Time::fun(Date& d)
{
cout << d._year << d._month << d._day;
}
class Time;
Date::Date(int year, int month, int day) :_year(year), _month(month), _day(day) {}
void Date::SetTimeOfDate(int hour, int minute, int second)
{
_t._hour = hour;
_t._minute = minute;
_t._second = second;
}
void test()
{
Date d;
d.SetTimeOfDate(1, 1, 1);
Time t;
t.fun(d);
}
4. 内部类
- 如果一个类定义在另一个类的内部,就叫做内部类,这个内部类是个独立类,不属于外部类,也不能通过外部类的对象去调用内部类。
- 内部类是外部类的友元类,外部类对内部类没有任何优越的访问权限。
- 内部类定义在外部类的public、private、protected都是可以的;
- 内部类可以直接访问外部类的static、枚举成员,不需要外部类的对象/类名;
- sizeof(外部类)=外部类,与内部类无关。
class A
{
friend class C;
class B
{
public:
void setA(A& a)
{
a._a = _b;
_sa = 100;
}
private:
int _b = 2;
};
private:
int _a = 1;
static int _sa;
};
int A::_sa = 10;
class C {
public:
void setA(A& a)
{
a._a = _c;
a._sa = 20;
A::_sa = 30;
}
private:
int _c = 3;
};