✨✨欢迎大家来到Celia的博客✨✨
🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉
所属专栏:C++
一、再谈构造函数
- 构造函数除了可以在函数体内对成员变量进行赋值这种方法外,还可以通过参数列表这种方法对其进行初始化。初始化列表的使用方式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后面跟⼀个放在括号中的初始值或表达式。
//初始化列表使用方式 Date(int year = 2000, int month = 6, int day = 1) :_year (year), _month(month), _day(day) { //函数体 }
初始化列表在语法上可以理解为成员变量定义的地方,所以每个成员变量在初始化列表中只能出现一次。
成员变量中:引用、const修饰的变量、没有默认构造函数的自定义类型必须在初始化列表中进行初始化。
在类中成员变量声明的部分,可以给缺省值,这个缺省值会给没有显式在初始化列表中的成员使用(C++11版本支持)。
class Date { public: //构造函数 Date(int year, int month, int day) :_year (year), _month(month), {} private: int _year = 2000;//缺省值 int _month = 10; int _day = 11;//_day会初始化为11,因为初始化列表中没有显式初始化_day };
所有对象的成员变量在调用构造函数时,都会走初始化列表,然后再执行函数体。也就是说,初始化列表无论如何都会执行,所以在书写构造函数时,尽量使用初始化列表。
初始化列表中的初始化顺序和成员变量的声明顺序一致,和初始化列表的顺序无关。
二、类型转换
C++支持内置类型隐式转换成自定义类型。想要实现这一点,需要有参的构造函数。
class Date
{
public:
//构造函数
Date(int year = 2000, int month = 6, int day = 1)
:_year (year),
_month(month),
_day(day){}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1 = 1;//单个参数的隐式类型转换,只会初始化_year
Date d2 = { 10,2,2 };//多个参数的隐式类型转换
return 0;
}
构造函数前面加explicit就不再支持隐式类型转换了:
//构造函数
explicit Date(int year = 2000, int month = 6, int day = 1)
:_year (year),
_month(month),
_day(day){}
int main()
{
Date d1 = 1;//error
Date d2 = { 10,2,2 };//error
return 0;
}
三、static成员
- static修饰的成员变量,称为静态变量,为该类的所有对象共享,必须在类外初始化。
class Sum { public: Sum() { sum += val; val++; } static int val; static int sum; }; //在类外进行指定类域初始化 int Sum::val = 1; int Sum::sum = 0;
静态成员变量不属于对象,存放在静态区。
用static修饰的成员函数,称为静态成员函数,静态成员函数没有this指针。
静态成员函数中可以访问其他的静态成员函数和变量,但是不能访问非静态的成员变量和成员函数,因为没有this指针。
非静态的成员函数可以任意访问静态的成员函数和成员变量。
静态成员变量或函数可以通过 类名::成员名 或 对象. 成员名来访问。
静态成员也受 public、private、protected访问限定符的限制。
静态成员变量不能在声明的时候给缺省值,因为静态成员不属于对象,不会走初始化列表。
class Sum { public: Sum() { sum += val; val++; } static int val = 10;//error static int sum = 100;//error };
四、友元
友元能够突破访问限定符封装的方式,友元分为:友元函数、友元类。在函数声明时在前面加上friend,把这个声明放在类中的任意位置,友元函数/友元类中就可以访问该类的所有成员。
class Date
{
//友元函数声明
friend ostream& operator<<(ostream& out, const Date& date);
friend istream& operator>>(istream& in, Date& date);
public:
void Print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
//这两个函数可以直接访问类中的所有成员,包括private、protected
//重载输出
ostream& operator<<(ostream& out, const Date& date)
{
out << date._year << "年" << date._month << "月" << date._day << "日" << endl;
return out;
}
//重载输入
istream& operator>>(istream& in, Date& date)
{
cout << "请输入年、月、日:";
in >> date._year >> date._month >> date._day;
return in;
}
- 一个函数可以是多个类的友元函数。
- 友元类中的所有成员函数都是另一个类的友元函数 。
- 友元关系是单向的,不具有交换性,不具有传递性。
- 友元函数不是类的成员函数。
- 友元函数会破坏封装,不建议过多使用。
五、内部类
- 如果一个类定义在另一个类的内部,那么这个类就叫做内部类。内部类相当于在全局新定义了一个类,它是独立的。仅仅是受到了外部类类域和访问限定符的限制。故外部类的对象中,并不包含内部类。
- 内部类默认是外部类的友元类。可以任意访问外部类的成员。
class Solution {
private:
//内部类
class Sum
{
public:
Sum()
{
//一些操作.......
sum += val;
val++;
}
int val;
int sum;
};
public:
int a;
int b;
};
六、匿名对象
定义一个有名对象、匿名对象:
class Date
{
public:
void Print()
{
cout << _year << '/' << _month << '/' << _day << endl;
}
Date(int year = 2000, int month = 6, int day = 1)
:_year (year),
_month(month),
_day(day){}
private:
int _year;
int _month;
int _day;
};
int main()
{
//有名对象
Date date(2024,10,10);
//匿名对象
Date(2023,2,4);
return 0;
}
相比于有名对象,匿名对象省略了名字。匿名对象的生命周期为一行。一般临时定义一个对象当前用一下即可,就可以定义匿名对象。以下是一个使用场景:
#include <iostream>
class Adder {
private:
int value;
public:
Adder(int v) : value(v) {}
Adder add(int x) {
value += x;
return *this; // 返回*this以支持链式调用
}
void display() {
std::cout << "Sum: " << value << std::endl;
}
};
int main() {
// 使用匿名对象进行两个数字相加
Adder().add(5).add(3).display();
return 0;
}