再谈构造函数
在我们之前的构造函数中,编译器会通过构造函数,对对象中各个成员给出一个适合的初始值,但这并不能称之为初始化,只是进行赋值而已;因为初始化只能初始化一次,而构造函数内部可以进行无数次赋值;
初始化列表
初始化列表是用于构造函数中对类成员变量进行初始化的语法特性。
通过初始化列表,可以在对象被创建时就将成员变量初始化为指定的值,而不是在构造函数体内逐个赋值。
语法:初始化列表用冒号(:)跟随在构造函数的参数列表之后,并且在构造函数体之前。
在初始化列表中,成员变量按照声明顺序列出,并使用逗号进行隔开。
每个成员变量的初始化由成员变量名后跟一个圆括号和初始值或者调用其他构造函数来完成。
试验:
class A { private: int _a; public: A(int a = 1) :_a(a) { } /*A(int* a) :_a(a) { }*/ A(const A& a) { _a = a._a; cout << "A(const A& a)" << endl; } ~A() { cout << "~A()" << endl; } }; class Date { private: int _year; int _month; int _day; int& _def; const int _n; public: Date(int year, int month = 1, int day = 1) :_year(year), _month(month), _day(day), _def(year), _n(10) { } }; int main() { Date d1=2023; Date d2 = (2023, 11, 4); Date d3 = { 2023, 11, 4 }; return 0; }
对const成员和引用成员进行测试:
Date的成员变量
Date类的构造函数
定义一个对象并初始化为(2023,10,23);
对于引用和const变量来说,都必须进行初始化;
规范写法:
成员变量中有自定义类型时:
成员的顺序:
初始化列表没写全的话:
如果自定义类型不是默认构造函数的话:
对于自定义类型成员变量的类对象,可以:
隐式类型转换
多个参数时
explicit关键字
这是一个修饰符,用于修饰类的构造函数。当一个构造函数被explicit修饰时,他将被标记为显示构造函数,意味着该构造函数无法进行隐式类型转换。
static成员
静态类成员:静态类成员是被类所有对象所共享的成员变量。它们被声明为静态成员后,在内存中只有一个副本存在,并且在任何实例化对象之前就已经存在了。静态类成员必须在类的外部进行初始化定义。
静态成员函数:静态成员函数不在特定的对象上操作,它们没有this指针,可以直接通过类名来访问。
class A { public: A() { count++; } A(const A& a1) { count++; } ~A() { cout << "~A()" << endl; } //调取count成员变量的函数 //静态成员函数,特点:没有this指针 static int GetCount() { return count; } private: //声明 static int count; }; //定义 int A::count = 0;
友元类
友元类是描述两个类之间的特殊关系;
当一个类是另一个类的友元类时,则该类可以访问另一个类的私有成员。
通过在类的声明中使用friend关键字来声明友元类。
class Time { public: friend class Date; //在Time中声明Date类,在Date中可以直接访问Time的成员变量 Time(int hour=1,int mintue=0,int sec=0) :_hour(hour), _mintue(mintue), _sec(sec) {} private: int _hour; int _mintue; int _sec; }; class Date { private: int _year; int _month; int _day; Time _t; public: Date(int year, int month, int day) :_year(year), _month(month), _day(day) { } void SetTime(int hour, int minute, int sec) { //可以直接访问私有的成员变量 _t._hour = hour; _t._mintue = minute; _t._sec = sec; } };
内部类
内部类是一个类的内部定义的另一个类。内部类可以访问外部类的所有成员,包括私有成员,而外部类不能直接访问内部类的成员。
class A { private: static int k; int h; public: class B//B天生为A的友元 { public: void f(const A& a) { cout << k << endl;//k是静态成员,可以直接使用 cout << a.h << endl;//h是非静态成员,需要有明确的类对象 } }; ~A() { cout << "~A()" << endl; } }; int A::k = 1; int main() { A::B b;//B在A类中需要加上作用域符 b.f(A());//A()是匿名对象 return 0; }
匿名对象
匿名对象是在使用过程中直接创建的没有具体名称的对象。
它们通常用于临时执行某个方法或操作,或者作为方法的返回值。
语法:ClassName();
实例:
class Foo() { public: void display() { cout<<"this is a Foo"<<endl; } } int main() { Foo().display(); }
拷贝函数时的一些优化
class A { private: int _a; public: A(int a=1) :_a(a) { cout << "A(int a)" << endl; } A(const A& a) { cout << "A(const A& a)" << endl; } A& operator=(const A& a) { cout << "A& operator=(const A& a)" << endl; if (this != &a) { _a = a._a; } return *this; } ~A() { cout << "~A()" << endl; } }; void func1(A aa) { cout << "func()" << endl; } A func2() { A aa; return aa; } A func3(A aa) { return aa; }