目录
1.const成员
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this 指针,表明在该成员函数中不能对类的任何成员进行修改
如果你的this指针不会被修改,都推荐加一个const
//有2个参数一个是隐含的this指针,const修饰的是this,另一个是cmp
//即bool operator==(Date& this(隐含),Date& cmp)const
bool operator==(Date& cmp)const//const修饰成员函数
{
return _year == cmp._year &&
_month == cmp._month &&
_day == cmp._day;
}
2.构造函数的补充
1.构造函数体赋值
构造函数体中的语句只能将其称作为赋初值,不能称作初始化,初始化定义应该是只能初始化一次,而构造函数体内可以多次赋值(就像下面代码_day先赋值5再赋值我们给的参数)
class Date
{
public:
Date(int year=2022, int month=2, int day=2)
{
_year = year;
_month = month;
_day=5;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
2.初始化列表
- 格式: 以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式
- 说明:每个成员变量只能初始化一次,{}即是构造函数体赋值所有可以多次赋值。(初始化列表是成员变量的定义)
class Date
{
public:
Date(int year = 2022, int month = 2, int day = 2)
//有三种必须在初始化列表初始化
:_year(1)
,_month(month)
,_day(day)
{}//构造函数体赋值
private:
int _year;
int _month;
int _day;
};
- 必须放在初始化列表位置进行初始化有3个:引用成员变量,const成员变量,自定义类型成员(该类没有默认构造函数)因为它们都是需要定义;初始化列表是成员变量的定义;
- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化;(因为初始化列表是定义)
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关(调试如下)
class A
{
public:
A(int a=10)
{
cout << "A" << endl;
_a = a;
}
private:
int _a;
};
class Date
{
public:
//可以理解成,一个对象的成员变量在初始化列表是成员变量的定义
//这个可以算是初始化列表和函数体内初始化不同的地方,也是它价值的体现(有三种必须在初始化列表初始化)
Date(int year = 2022, int month = 2, int day = 2)
//有三种必须在初始化列表初始化
:_year(year)
, _day(day)
, _month(month)
, _c(year)//引用成员变量
, _n(10)//const成员变量
, _a(20)//自定义类型成员(类没有默认构造函数)
{
_year = year;//函数结构体内初始化
//不能在函数体内初始化,必须使用初始化列表初始化
//函数体内初始化并不是初始化,而是对成员变量的再处理
//_c = year;
//_n = 10;
//_a = 20;
}
private:
//成员变量声明的次序就是初始化列表中的初始化顺序,与其它在初始化列表的先后顺序无关
//成员变量声明
int _year;
int _month;
int _day;
//必须在定义时候初始化
const int _n;
int& _c;
A _a;
};
3.explicit关键字
对于单个参数的构造函数,还具有类型转换的作用
- 单个参数的构造函数,支持隐式类型转换
- 早时期:先创造一个临时变量A tmp(2),再拷贝构造A a2(tmp);现在编译器做了优化:A a2(2);
- explicit,不想发生隐式类型转换加一个explicit,即不能使用A a2=2这样的形式;
class A
{
public:
//explicit不想发生隐式类型转换加一个explicit
A(int a=100)
{
_a = a;
}
explicit A(int a=100)
{
_a = a;
}
private:
int _a;
};
int main()
{
A a1(1);
//单个参数的构造函数,支持隐式类型转换
A a2 = 2;//早时期:先创造一个临时变量A tmp(2),再拷贝构造A a2(tmp);现在编译器做了优化:A a2(2);
A(3);//构造匿名对象,生命周期就在这一行,生命周期结束调析构;
A();
return 0;
}
3.C++11 的成员初始化新玩法(声明缺省值)
说明:如果没有初始化列表初始化,那么就会使用声明缺省值来初始值;即看代码中:_a(a) ,_p(p)使用了列表初始化,那么不使用声明缺省值,但是arr和_b没有初始化那么使用声明缺省值;
#include <iostream>
using namespace std;
class B
{
public:
B(int x = 0)
{
_x = x;
}
private:
int _x;
};
class A
{
public:
A(int a=1,int* p=nullptr)
:_a(a)
,_p(p)
{
}
private:
//声明缺省值
int _a=0;
int* _p=nullptr;
int* arr = (int*)malloc(sizeof(int));
B _b=6;
};
int main()
{
A a;
return 0;
}
4.友元(友元函数,友元类(内部类))
1.友元函数
友元函数可访问类的私有和保护成员,但不是类的成员函数
- 友元函数不能用const修饰
- 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
- 一个函数可以是多个类的友元函数
- 友元函数的调用与普通函数的调用和原理相同
#include <iostream> using namespace std; class Date { friend ostream& operator<<(ostream& out, const Date& d); friend istream& operator>>(istream& in, Date& d); public: 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() { return 0; }
2. 友元类
- 友元函数的调用与普通函数的调用和原理相同
友元函数可访问类的私有和保护成员,但不是类的成员函数
-
友元关系是单向的,不具有交换性;Dates是Time的友元,Time不是Date的友元
-
友元关系不能传递,如果B是A的友元,C是B的友元,则不能说明C时A的友元
class Date; // 前置声明
class Time
{
friend class Date; // 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量
public:
Time(int hour, int minute, int second)
: _hour(hour)
, _minute(minute)
, _second(second)
{}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
: _year(year)
, _month(month)
, _day(day)
{}
void SetTimeOfDate(int hour, int minute, int second)
{
// 直接访问时间类私有的成员变量
_t._hour = hour;
_t._minute = minute;
_t.second = second;
}
private:
int _year;
int _month;
int _day;
Time _t;
};
3.内部类(了解,不怎么用)
- 内部类可以定义在外部类的public、protected、private都是可以的。
- 注意内部类可以直接访问外部类中的static、枚举成员,不需要外部类的对象/类名
- sizeof(外部类)=外部类,和内部类没有任何关系。
class A
{
private:
static int k;
int h;
public:
class B
{
public:
void foo(const A& a)
{
cout << k << endl;//OK
cout << a.h << endl;//OK
}
};
};
int A::k = 1;
int main()
{
A::B b;
b.foo(A());
return 0;
}
如果有没有理解的,评论区我会回复