构造函数初始化列表
我们创建一个类,借助类的构造函数去初始化数据,其实这不是真正的初始化,因为真正的初始化只会有一次,而构造函数里面可以多次赋值,最重要的是有一些类型的数据,构造函数内是无法完成初始化的,例如const修饰的变量,引用类型。
class A {
public:
A() {
a = 10;
b = a;
}
private:
const int a;
const int& b;
};
int main() {
A a1;
return 0;
}
显然这种情况构造函数是无法解决的,那么之前C++是怎么解决这种问题的呢?其实构造函数有一个真正初始化数据的地方,叫做初始化列表。
class A {
public:
A()
:a(10)
, b(a)
{
}
private:
const int a;
const int& b;
};
int main() {
A a1;
return 0;
}
- 每个成员变量在初始化列表只能出现一次。
- 引用成员变量,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:
A _aobj; // 没有默认构造函数
int& _ref; // 引用
const int _n; // const
};
static成员
类的static修饰的成员变量被称为静态变量,其实是不属于某个对象的,它是属于类的。
class A {
public:
A() {
ret++;//创建一个类就统计一次
}
static int getret() { //静态成员函数里面只能存在静态成员变量
return ret;
}
private:
static int ret; //静态成员变量
};
int A::ret = 0;//类里面的静态成员变量只能在类外面初始化,C++规定
int main() {
A a1;
A a2;
A a3;
A a4;
cout << A::getret() << endl;//静态成员函数可以直接访问
cout << a1.getret() << endl;//每个对象都能访问到属于类的成员变量
cout << a2.getret() << endl;
cout << a3.getret() << endl;
return 0;
}
特性:
- 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
- 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
- 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
- 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
- 静态成员也是类的成员,受public、protected、private 访问限定符的限制
友元
友元函数
现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。
class Date
{
//友元函数声明方式,关键字friend
friend ostream& operator<<(ostream& _cout, const Date& d);
friend istream& operator>>(istream& _cin, Date& d);
public:
Date(int year = 2000, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day<<"日"<<endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
int main()
{
Date d;
cin >> d;
cout << d << endl;
return 0;
}
友元类
友元类的关系是单向的,友元类的关系不能传递,如果C是B的友元, B是A的友元,则不能说明C时A的友元。
class A {
//友元类的声明方式
friend class B;
public:
A()
:a(1)
,b(2)
{
}
private:
int a;
int b;
};
class B {
public:
B()
:a(10)
,b(20)
{
}
void show() {
cout << a << endl;
cout << b << endl;
cout << a1.a << endl;//只有B类可以访问A类,A类不能访问B类
cout << a1.b << endl;
}
private:
int a;
int b;
A a1;
};
int main()
{
B bb;
bb.show();
return 0;
}
内部类
内部类是指一个类声明在另一个类里面,内部类是一个独立的类,不属于外部类,外部类天生就是内部类的友元类,可以访问外部类的成员变量,但是内部类不是外部类的友元类,内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
class A {
public:
A()
:a(10)
{
}
class B {
public:
B()
:bb(30)
{
}
void show(const A& a1) {
cout << k << endl;
cout << a1.a << endl;
}
private:
int bb;
};
private:
int a;
static int k;
};
int A::k = 11;
int main() {
A a;
A::B b1;
b1.show(a);
return 0;
}
匿名对象
class A {
public:
A() {
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
};
int main() {
A();//匿名对象、作用域只在这一行
return 0;
}
拷贝对象时的编译器优化
class A {
public:
A(int n)
:a(n)
{
}
private:
int a;
};
void fun1(A a) {
}
void fun2(const A& a) {
}
int main() {
A a = 1;//这是一个类型转换,先临时构造一个A类型的临时变量,1赋值给临时变量,然后临时变量拷贝构造给a
//所以会调用一个构造和一个拷贝构造,但是编译器会直接优化为一个构造函数
fun1(a);//没有优化,编译器优化只会在一个连续的指令
fun1(1);//构造函数+拷贝构造-》优化为直接构造
fun1(A(1));//构造函数+拷贝构造-》优化为直接构造
//引用类型没有优化
fun2(a);
fun2(1);
fun2(A(1));
return 0;
}
类和对象就给大家介绍到这里,如果对您有所帮助,留一个赞吧!