== 1.类的6个默认成员函数==
1.1 构造函数主要完成初始化工作
1.2 析构函数主要完成清理工作
1.3 拷贝构造是使用同类对象初始化创建对象
1.4 赋值重载主要是把一个对象赋值给另一个对象
1.5 普通对象取地址
1.6 const对象取地址
1.7.static成员
== 2.构造函数==
1.构造函数是特殊的成员函数,构造函数的主任务并不是开辟空间创建对象,而是对象的初始化。
其特征如下:
1.函数名与类名相同。
2.无返回值。
3.对象实力化时编译器自动调用对应的构造函数
4.构造函数可以重载
class /* 定义类的关键字*/ Date //类的名字
{ // { }中为类的主体
//类体:由成员变量和成员函数组成
//类中的数据称为类的属性或者成员变量。
//类中的函数称为类的方法或者成员函数。
// 声明和定义最好不要都放在类体中 声明在.h中 定义在.cpp中
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month= month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
d1.SetDate(2012,12,12);
d2.SetDate(2012,11,10);
d1.Display();
d2.Display();
return 0;
}
5.如果·类没有显示定义构造函数,则C++编译器会自动生成一个无参数的默认构造函数,一旦用户显示定义将不再生成
class Date
{
public:
private:
int _year;
int _month;
int _day;
};
void Test ()
{
Date d;
}
6.无参函数和全缺省函数都称为默认函数,并且只能有一个
当然定义的时候最好使用全缺省函数
class /* 定义类的关键字*/ Date //类的名字
{ // { }中为类的主体
//类体:由成员变量和成员函数组成
//类中的数据称为类的属性或者成员变量。
//类中的函数称为类的方法或者成员函数。
// 声明和定义最好不要都放在类体中 声明在.h中 定义在.cpp中
public:
Date(int year = 1, int month = 1 , int day= 1)//常用的写法
{
_year = year;
_month= month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1;
}
7.初始化列表
类和对象有两种初始化方式
1.函数体内赋值初始化
2.初始化列表
class Date
{
public:
Date(int year = 1, int mouth = 1, int day = 1)
{
//函数体内初始化
_year = year;
_mouth = mouth;
_day = day;
}
Date(int year = 1, int mouth = 1, int day = 1)
:_year(year)
,_month(month)
,_day(day)
{
//初始化列表
}
private:
int _year;
int _month;
int _day;
};
1.每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
2.类中包含以下成员,必须放在初始化列表位置进行初始化:
== 引用成员变量==
== const成员变量==
自定义类型成员(该类没有默认构造函数)
class A
{
public:
//初始化列表是成员函数定义的地方
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int ref)
:_aobj(a)
,_ref(ref)
,_n(10)
{}
private: //因为他们都必须在定义的时候初始化,而初始化列表是成员变量定义的位置。
A _aobj; //没有默认构造函数
int& _ref; // 引 用
const int _n; // const
};
3.尽量使用初始化列表初始化,会更加高效。因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使 用初始化列表初始化。
class Time
{
public:
Time(int hour = 0)
:_hour(hour)
{
cout << "Time()" << endl;
}
private:
int _hour;
};
class Date
{
public:
Date(int day)
{}
private:
int _day; Time _t;
};
int main()
{
Date d(1);
}
4.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
== 3.析构函数==
其特征如下:
1.析构函数名是在类名前加上字符 ~。
2.无参数无返回值。
3.一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
4.对象生命周期结束时,C++编译系统系统自动调用析构函数。
class Date
{
public:
Date(int year = 1, int mouth = 1, int day = 1)
{
_year = year;
_mouth = mouth;
_day = day;
~Date() //析构函数 (一般清理 动态资源)
//1.无参数 无返回值
{ //2.一个类有且只有一个析构函数。若未显示定义
//系统会自动生成默认的析构函数
//3.对象生命周期结束时,C++编译系统自动调用析构函数
//4.Date类没有资源需要清理,所以析构函数类什么都不用写
}
private:
};
还有先构造的后析构哦
== 4.拷贝构造函数==
其特征如下:
1.拷贝构造函数是构造函数的一个重载形式。
2.拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用。(如图)
3.若未显示定义,系统生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝我们叫做浅拷贝,或者值拷贝。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
int main()
{
Date d1;
Date d2(d1);
return 0;
}
& 千万不要忘记
== 5.赋值运算符重载==
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
1.不能通过连接其他符号来创建新的操作符:比如operator@
2.重载操作符必须有一个类类型或者枚举类型的操作数
3.用于内置类型的操作符,其含义不能改变,例如:内置的整型+,不 能改变其含义作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参
4.(.*) 、:: 、sizeof 、?: 、(. )注意以上5个运算符不能重载。
赋值运算符主要有四点:
1.参数类型
2.返回值
3.检测是否自己给自己赋值
4.返回*this
5.一个类如果没有显式定义赋值运算符重载,编译器也会生成一个,完成对象按字节序的值拷贝。
应用:日期类的实现
#include<iostream>
using namespace std;
class Date
{
public:
int GetMonthDays(int year, int month)
{
int MonthDays[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month == 2
&&((year % 4 == 0 && year % 100 != 0 )||year % 400 == 0) )
{
return 29;
}
else
{
return MonthDays[month];
}
}
Date (int year = 0, int month = 1, int day = 1)
{
if (year >= 0
&& month > 0 && month < 13
&& day > 0 && day <= GetMonthDays(year, month))
{
_year = year;
_month = month;
_day = day;
}
else
{
cout << "非法日期" << endl;
}
}
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
cout << "调用我啦" << endl;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//d1 = d3 d3赋值给d1 d1.operator=(&d1,d3)
//Date& operator = (const Date &d)//d1传给隐含的this d3传给d
// //建议传引用 提高效率
// //建议加const进行保护
//{
// if (this != &d)
// {
// this->_year = d._year;
// this->_month = d._month;
// this->_day = d._day;
// }
// return *this;
//}
// 1.日期 += 天数
//d1+100天 d1.operator+(&d1 , 100);
Date operator+=(int day) //另一个是隐含的
{
_day += day;
while (_day > GetMonthDays(_year ,_month))
{
//减掉当期月的天数
_day -= GetMonthDays(_year, _month);
++_month;//月进1
if (_month == 13)
{
_year++;//月满了 年进1
_month = 1;//月置1
}
}
return *this; //也可以用引用返回
}
//2.日期 + 天数 不能改变日期
Date operator+(int day)
{
/*Date ret(*this); // 不改变的d1 所以创建一个临时对象
//ret 就是拷贝构造出来的d1 ret是可以改变的 *this就是d1
ret._day += day;
while (ret._day > GetMonthDays(ret._year, ret._month))
{
ret._day -= GetMonthDays(ret._year, ret._month);
++ret._month;//月进1
if (ret._month == 13)
{
ret._year++;//月满了 年进1
ret._month = 1;//月置1
}
}*/
Date ret(*this);
ret += day;
return ret;//返回临时对象
}
// 3.日期 -= 天数
Date operator -= (int day)
{
if (day < 0)
{
day = -day;
return *this;
}
_day -= day;
while (_day <= 0)//=0表示 0天的时候也会退回上一个月
{
--_month;
if (_month == 0)
{
--_year;
_month = 12;
}
_day += GetMonthDays(_year, _month);
}
return *this;
}
// 4.日期 - 天数
Date operator - (int day)
{
Date ret(*this);
ret -= day;
return ret;
}
//5. ++前置
//d1.operator++(&d1)
Date& operator++ ()
{
*this += 1;
return *this;
}
//6. 后置++ 返回++之前的值
//d1.operator++(&d1 , 0)
Date operator++ (int i) //为了区分与前置++ 这里加一个参数
{
//返回++之前的值
Date ret(*this);//把++之前的值拷贝构造保存起来
*this += 1;
return ret;//出了作用域返回值就不存在了 不能用引用返回
}
/*bool operator*/
//7. d1 < d2
bool operator < (const Date& d)
{
if ((_year < d._year)
|| (_year == d._year && _month < d._month)
|| (_year == d._year && _month == d._month && _day < d._day))
{
return true;
}
return false;
}
//8.d1 > d2
bool operator > (const Date& d)
{
if ((_year > d._year)
|| (_year == d._year && _month > d._month)
|| (_year == d._year && _month == d._month && _day > d._day))
{
return true;
}
return false;
}
//d1 == d2 //如果Date加了 时-分-秒 成员 下面的改动最小
bool operator == (const Date& d)
{
return _year == d._year && _month == d._month && _day == d._day;
}
//9.d1 <= d2
bool operator <= (const Date& d)
{
return *this < d || *this == d ;
}
//10. d1 >= d2
bool operator >= (const Date& d)
{
return !(*this < d);
}
//11.d1 != d2
bool operator != (const Date& d)
{
return !(*this == d);
}
//12. 日期 - 日期
int operator - (const Date& d)
{
int flag = -1;
Date min = *this;
Date max = d;
if (*this > d)
{
flag = 1;
min = d;
max = *this;
}
int n = 0;
while (min != max)
{
++n ;
++min ;
}
return n*flag ;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2012, 3,19);
d1.Print();
Date d2(2020, 4, 20);
d2.Print();
//Date d3 = d1 - 19; // 不改变原值
//d1.Print();
//d3.Print();
//Date d2 = d1 -= 19;//改变原值
//d1.Print();
//d2.Print();
/*Date d2(d1);
d2.Print();
Date d4 = d1++;
d1.Print();
d4.Print();
Date d5 = ++d2;
d2.Print();
d5.Print();*/
Date d6 = d2 - d1;
/* d6.Print();*/
cout << d1 - d2 << endl;
/*日期+天数 运算符重载
日期-天数
日期+=天数
日期-=天数
日期-日期*/
return 0;
}
日期 += 天数 日期+天数
日期-=天数 日期-天数
前置++ 后置++
== 6.成员函数const==
将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this 指针,表明在该成员函数中不能对类的任何成员进行修改。
== 7.static成员==
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的 成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化
实现一个类,计算中程序中创建出了多少个类对象。
class A
{
public:
A()
{
++n;
}
A(const A& t)
{
++n;
}
Get N()
{
return n;
}
private:
static int n ;
};
int A :: int n = 0 ;//为什么不在构造函数初始化,因为n不是属于某个对象,n属于这个类,
//与属于这个类的所有对象
void f (A a)
{
}
int main()
{
A a1;
A a2;
A a3(a2);
f(a1);
cout<< n << endl;
return 0 ;
}
1.静态成员为所有类对象所共享,不属于某个具体的实例
2.静态成员变量必须在类外定义,定义时不添加static关键字
3.类静态成员即可用类名::静态成员或者对象.静态成员来访问
4.静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5.静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值