构造函数:
1、构造函数可以用初始化列表赋值,:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
2、每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
3、类中包含以下成员,必须放在初始化列表位置进行初始化: 引用成员变量 const成员变量 自定义类型成员(且该类没有默认构造函数时)
4、尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。
5、成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
6、C++11支持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显示在初始化列表初始化的成员用的。
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:
A _aobj;
};
类型转换:
1、C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型作为参数的构造函数。
2、构造函数前面加explicit就不再支持隐式类型转换。
3、类类型的对象之间也可以隐式转换,需要相应的构造函数支持。
Static成员:
1、用static修饰的成员变量,称之为静态成员变量。静态成员变量一定要在类外进行初始化。
2、静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。
3、用static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。
4、静态成员函数可以访问其他的静态成员,没有隐藏的this指针,不能访问任何非静态成员。
5、非静态的成员函数,可以访问任何静态成员变量和静态成员函数。
6、突破类域可以访问静态成员,可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。
7、静态成员也是类的成员,受public、protectde、private访问限定符的限制。
8、静态成员变量不能在声明位置给缺省值初始化,因为缺省值是给构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表。
:实现一个类,计算程序中创建出了多少个类对象。
class A
{
public:
A() { ++_scount; }
A(const A& t) { ++_scount; }
~A() { --_scount; }
static int GetACount() { return _scount; }
private:
static int _scount;
};
int A::_scount = 0;
void TestA()
{
cout << A::GetACount() << endl;
A a1, a2;
A a3(a1);
cout << A::GetACount() << endl;
}
友元
友元分为:友元函数和友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到一个类里面。
外部友元函数可访问类的私有和保护成员,友元函数仅仅是一种声明,他不是类的成员函数。
友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
一个函数可以是多个类的友元函数。
友元类中的函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员。
友元类的关系是单向的,不具有交换性,比如A是B的友元,但B不是A的友元。
友元类关系不能传递,比如A是B的友元,B是C的友元,但A不是C的友元。
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
, _day(day)
{}
// d1 << cout; -> d1.operator<<(&d1, cout); 不符合常规调用
// 因为成员函数第一个参数一定是隐藏的this,所以d1必须放在<<的左侧
ostream& operator<<(ostream& _cout)
{
_cout << _year << "-" << _month << "-" << _day << endl;
return _cout;
}
private:
int _year;
int _month;
int _day;
}
内部类:
如果一个类定义在另一个类内部,这个类就叫内部类,他是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。
内部类默认是外部类的友元类。
内部类本质也是一种封装,如果A实现是为了B使用,那么可以考虑把A设计成B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。
class A
{
private:
static int k;
int h;
public:
class B // B天生就是A的友元
{
public:
void foo(const A& a)
{
cout << k << endl;//OK
cout << a.h << endl;//OK
}
};
};
int A::k = 1;
int main()
{
A::B b;
b.foo(A());
return 0;
}
匿名对象:
用类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。
匿名对象生命周期只在当前一行,之后会自动析构,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。