目录
初始化列表
static成员
C++11对于非静态成员变量初始化
友元
友元函数
友元类
总结
我们知道,在学习构造函数时,我们知道对象的成员变量的初始化我们是在构造函数函数体内进行初始化的,还有没有其它初始化成员变量的方法呢?
初始化列表就是我们要学习的第二个初始化的方法。
在学习初始化列表之前,我们先对以往的在构造函数内部对成员变量进行初始化的操作进行分析,我们直接给出结论,我们称在类内部的成员变量只是对成员变量进行了声明,而没有进行定义,如图所示:
我们在日期类内部声明了三个成员变量,_year,_month,_day,切记,这里只是对三个成员变量进行了声明,成员变量的定义分为两种情况:
1.如果我们在构造函数体内进行成员变量的初始化操作,那么在进行初始化时,成员变量已经完成了定义,函数体内只是在进行进行变量的赋值而已。因此就这一现象我们不难产生疑问?如果在函数体内对成员变量进行赋值时,此时变量已经完成了定义,此时的赋值操作就相当于是在成员变量定义之后才对成员变量进行了初始化操作,那么对于const成员变量,引用成员变量,没有默认构造函数的自定义成员变量这些在定义时必须初始化的成员变量还能用这种初始化方式进行初始化吗?当然不行,此时我们就得用第二种方式进行成员变量的初始化操作。
2.如果我们使用初始化列表进行成员变量的初始化操作,就相当于是在变量定义时,对成员变量进行了初始化操作,这对于上述三种必须在定义时就必须进行初始化的成员变量而言是可行的。
相关示例代码如下:
class A {
public:
A(int a)
{
_a = a;
}
private:
int _a;
};
class Date {
public:
Date(int year,int month,int day,int A)
:_year(year)
,_month(month)
,_day(day)
,_a(10)
,a(A)
,_aa(10)
{}
private:
int _year;
int _month;
int _day;
const int _a;
int& a;
A _aa;
};
重点:对于自定义类型而言,还有一个要注意的问题:当自定义类型成员变量没有默认的构造函数时,我们必须在定义时进行初始化,所以我们必须用初始化列表对其进行初始化。但是当自定义类型成员变量有默认的构造函数时,我们在定义时可以不用初始化,在定义之后初始化也可以,也就意味着有了默认构造函数的成员变量可以在构造函数的函数体内进行初始化。但是,当我们在构造函数体内对有默认构造函数的成员变量初始化时,编译器同时也默认生成了初始化列表调用了自定义成员变量的默认构造函数对其进行了初始化。所以就会存在不管自定义类型的成员变量是否存在默认的构造函数,我们都会生成初始化列表对自定义类型成员变量进行初始化,所以我们干脆让其都在初始化列表中初始化,没有默认构造函数我们自己生成初始化列表为其初始化,有默认构造函数,编译器帮助我们自动生成初始化列表完成初始化。
总结:对于内置类型的成员变量和自定义类型成员变量(有默认构造函数),在构造函数体内部和初始化列表中都可以进行初始化操作,对于const成员变量,引用成员变量,自定义类型成员变量(没有默认构造函数),我们在初始化列表中完成初始化,为了统一我们规定所有的成员变量都在初始化列表中进行初始化。
之前我们也学习过static关键字,我们知道static可以改变变量的声明周期,比如可以在局部变量之前加上static,从而使局部变量拥有了和全局变量一样的生命周期,在C++也有static关键字,那么它的作用是什么呢?
其实,C++中的static关键字的作用和我们之前学习的是一样的,同样也可以改变变量的生命周期,可以是成员变量的周期,使之属于类及所有的对象,生命周期在整个程序运行期间。
先看如下代码,当静态成员变量为public时:
class A {
public:
static int _c;
A(int a=1)
{
_a = a;
}
private:
int _a;
};
//静态成员变量必须在类外进行定义初始化
int A::_c = 1;
int main()
{
//再类外实现对静态成员变量的访问,当静态成员变量为pulbic时
A a;
cout << a._c << endl;
cout << A::_c << endl;
return 0;
}
解析:静态成员变量必须在类外进行定义初始化。当静态成员变量为public修饰时,我们在类外进行访问,可以通过对象.,类::方式去访问。
当静态成员变量用private修饰时,在类外肯定是不能访问的,所以我们必须在类内提供公共的接口去访问,先看下列代码:
class A {
public:
A(int a=1)
{
_a = a;
}
//提供公共的接口,普通的成员函数
void print()
{
cout << _c << endl;
}
//提供公共的接口,static静态成员函数,但是static静态成员函数没有this指针,所以不能访问非静态成员变量,只能访问静态成员变量和成员函数
static void print1()
{
cout << _c << endl;
}
private:
int _a;
static int _c;
};
int A::_c = 3;
int main()
{
//在类外实现对静态成员变量的访问,当静态成员变量为private时
A a;
//1.通过对象.的方式去访问
a.print();
//2.通过类::方式去访问
A::print1();
return 0;
}
解析:如果是private修饰的静态成员变量,我们在类外可以通过公共的接口,即普通的成员函数和静态的成员函数进行访问,但是静态的成员函数因为没有隐藏的this指针,所以只能访问静态成员变量和成员函数,不能访问非静态成员变量。
总而言之,静态的成员函数和成员变量都属于整个类和所有对象,都可以可以使用对象.和类::的方式去访问。
我们在学习构造函数时,我们学写了编译器生成的默认构造函数,我们知道默认构造函数对于内置类型是不做初始化处理的,只对自定义类型进行初始化处理,为了改善这种情况,C++11发明了一种新的语法。就是给非静态成员变量声明时顺便给予缺省值。
相关代码如下:
class A
{
public:
void print()
{
cout << a << endl;
}
private:
int a = 10;
int* p =(int*) malloc(40);
};
int main()
{
A a;
a.print();
}
整个过程,就相当于是给自定义类型给予了缺省值,当构造函数的初始化列表没有给内置类型赋初始值时,就会使用这个初始值。
运行截图如下,我们发现内置类型确实使用了此缺省值。
友元的概念:友元是一种允许非类成员函数访问类的非公友成员的一种机制,友元可以是函数或者类,通过在类中用关键字friend说明该函数或者类,使得函数或者类获得其私有和保护成员的访问权限,在函数体中访问对象的成员,必须用对象.的方式访问。
直接看代码:
class B {
friend void print(B& b);
private:
int _b=666;
};
void print (B& b) {
cout << b._b << endl;
}
int main()
{
B b;
print(b);
}
运行截图如下:
注意: 1.友元函数可以访问类的私有和保护成员,但是它不是成员函数。
2.注意const不能修饰友元函数,因为友元函数不是成员函数,const只能修饰成员 函数。
3.友元函数就是一种普通的函数,用一般函数调用的方式调用即可。
直接看代码:
class B {
friend class A;
private:
int _b=888;
};
class A
{
public:
void print()
{
cout << b._b << endl;
}
private:
int _a = 10;
B b;
};
int main()
{
A a;
a.print();
}
再类B中,直接声明,类A是类B的友元类,那么类A就可以访问类B的非公有成员,运行截图如下:
注意: 1.友元类不具有交换性,声明类A是类B的友元,但此时类B不一定是类A的友元,只有声明了类B时类A的友元类之后,两者才可以互相访问彼此的非公有成员。
2.友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类的非公有成员。
到了这里类和对象的学习我们就可以告一段落了,类和对象细小的知识点太多,但是这些细小的知识点便是C++学习的精髓所在,望小伙伴们可以反复观看!
本期内容到此结束!^_^