类与对象(4)
1.初始化列表
我们前面学习了构造函数,可以对成员变量进行初始化。这里再学习一种新的构造方法:初始化列表。
格式:是以“ :”开始,以“ ,”隔开。
比如:
class Date
{
public:
Date(int year, int month, int day)
:_year(year)
,_month(month)
,_day(day)//初始化列表,可以一行写一个,也可以都写在一行(这里定义初始化)
{}
void Print()
{
cout << _year << "-" << _month << "-" << _day;
}
private:
//声明,不是定义!!!!
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2024, 7, 14);
d1.Print();
return 0;
}
1. 初始化列表在语法上可以理解为每个成员变量定义初始化的地方,不能多次定义,所以每个成员变量只能初始化一次。
2. 引用成员变量、const成员变量、没有默认构造的类类型变量都必须放在初始化列表进行初始化。否则,编译报错。
- 引用成员变量:
引用类型必须初始化,不初始化会报错。所以引用成员变量必须放在初始化列表中进行初始化。
class Time { public: Time(int hour, int m) :_hour(hour) ,_m(m) {} private: int _hour; const int _m; };
- const成员变量:
由于在语法上定义,在初始化列表中代表定义初始化,如果const没在初始化列表中进行初始化,而在其他地方进行初始化,那么会二次初始化,会报错。所以const修饰的成员变量也必须在初始化列表中进行初始化。
class Time { public: Time(int hour, int m) :_hour(hour) ,_m(m) {} private: int _hour; const int _m; };
- 没有默认构造的类类型变量:
首先,要知道每个成员变量都要走初始化列表(即使没有显式写在初始化列表),对于没有显式写在初始化列表的类类型的成员变量,会默认调用相应的默认构造函数。如果没有相应的默认构造函数,那就必须显式写在初始化列表进行定义初始化。
有默认构造:
class Date { public: Date(int year = 1, int month = 2, int day = 3)//_d的默认构造,有了就不用在初始化列表中写 :_year(year) ,_month(month) ,_day(day) {} void Print() { cout << _year << "-" << _month << "-" << _day; } private: int _year; int _month; int _day; }; class Time { public: Time(int hour, int m) :_hour(hour) ,_m(m) {} private: int _hour; const int _m; Date _d;//类类型的成员变量 };
无默认构造:
class Date { public: Date(int year, int month, int day)//无默认构造没救要在初始化列表中进行初始化 :_year(year) ,_month(month) ,_day(day) {} void Print() { cout << _year << "-" << _month << "-" << _day; } private: int _year; int _month; int _day; }; class Time { public: Time(int hour, int m, Date e) :_hour(hour) ,_m(m) ,_d(e)//进行初始化 {} private: int _hour; const int _m; Date _d; };
3. 如果在声明变量的时候给值是初始化吗?并不是,这只是初始化列表的缺省值。如果不在初始化列表进行初始化的成员会用这个缺省值进行初始化。
这样也方便了编译器对内置类型进行初始化,因为大部分编译器是不会对内置类型进行初始化的,打印出来是随机值
4. 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的先后顺序无关。
- 总结一下:
每个成员都要走初始化列表,每个构造函数都有初始化列表。
1. 显式写在初始化列表的成员
2. 没有显式写在初始化列表的成员
i. 声明的地方有缺省值用缺省值
ii. 没有缺省值
a. 内置类型看编译器,大概率随机值
b. 自定义类型调用默认构造函数,没有就编译报错
3. 引用成员变量、const成员变量、没有默认构造的类类型变量都必须放在初始化列表进行初始化。否则,编译报错。
2.static成员
1. 用static修饰的成员变量叫做静态成员变量,其定要在类外进行初始化。用static修饰的成员函数叫做静态成员函数,其没有this指针。
class T { public: T() { cout << "T()" << endl; } static int GetA() { b++;//报错,因为static函数无this指针 return a;//可以访问其他静态成员 } private: static int a; int b; }; int T::a = 1;//在类外进行初始化
2. 静态对象存放在静态区,所以所有类都可用,不属于某个具体的对象,不存在于对象中。但也受private、protected等访问限定符的限制。
3. 非静态的成员函数可以访问任意的静态成员变量和静态成员函数,但静态成员函数不能访问非静态的。
4. 访问静态成员变量和静态成员函数的方式:类名::静态成员(函数)或对象.静态成员(函数)
5. 不能在声明的时候给缺省值,因为静态成员不属于对象,不走初始化列表,是在类外面进行初始化的。
class T { public: T() { cout << "T()" << endl; } private: //static int a = 1;//不能在声明的时候给值 int b; }; int T::a = 1;//在类外进行初始化
3.友元
1. 友元可以突破访问限定符,让一个类或函数访问另一个类的私有或保护成员。友元分为友元类和友元函数,格式是在类或函数的声明前加friend,并把友元声明放在一个类中。
2. 友元函数仅仅是一个声明,并不是一个函数。
3. 一个函数可以是多个类的友元函数。
class D;//提前声明一下,不然下面func里的参数const D&编译器不知道找谁 class F { friend void func(const F& af, const D& dq);//多个类的友元函数 private: int a = 1; int b = 2; }; class D { friend void func(const F& af, const D& dq);//多个类的友元函数 private: int c = 3; int d = 4; }; void func(const F& af, const D& dq) { cout << af.a << endl; cout << dq.c << endl; } int main() { F f; D d; func(f, d); return 0; }
4. 友元类中的成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员。
class T { //友元声明 friend class G; private: int a = 1; int b = 2; }; class G { public: void func1(const T& aa) { cout << aa.a << endl; cout << c << endl; } void func2(const T& aa) { cout << aa.b << endl; cout << d << endl; } private: int c = 3; int d = 4; }; int main() { T t; G g; g.func1(t); g.func2(t); }
5. 友元类的关系是单向的,不具有交换性。比如B是A的友元,但A不是B的友元。
6. 友元类关系不能传递,如果A是B的友元,B是C的友元,但A不是B的友元。
7. 友元关系不宜多!
4.内部类
1. 一个类定义在另一个类中,叫做内部类。内部类是独立的,外部类定义的对象不包含内部类。
class A { public: class B { public: void func() { cout << c << endl; } private: int c; }; private: int a; int b; }; int main() { int n = sizeof(A);//结果是8,可以看出并没有算B中的大小。 cout << n << endl; return 0; }
2. 内部类默认是外部类的友元函数。
class A { public: class B { public: void func(const A& a) { cout << c << endl; cout << a.a << endl;//可以访问到A中的私有对象 } private: int c; }; private: int a; int b; }; int main() { int n = sizeof(A); cout << n << endl; return 0; }
3. 如果把内部类B放到private/protected位置,那么B就是A的专属内部类,其他地方都用不了。
5.匿名对象
1. 像 类型(实参)定义出来的对象叫做匿名对象,我们之前所用的 类型 对象名(实参)定义出来的叫有名对象。
2.匿名对象的生命周期只有他所在的那一行,下一行就会调用析构。
class A { public: A(int a = 0) :_a(a) { cout << "A(int a)" << endl; } ~A() { cout << "~A()" << endl; } private: int _a; }; int main() { //有名对象 A aa1; //匿名对象 A(); A(1); return 0; }
原文地址:https://blog.csdn.net/2301_79725612/article/details/140444840
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!