目录
一,构造函数
二,析构函数
三,拷贝构造函数
四,赋值运算符重载
五,日期类的实现
六,const成员
七,取地址及const取地址操作符重载
附
类的六个默认成员函数!
任何一个类,在不写的情况下,都会生成6个默认成员函数;
class Date{};
一,构造函数
构造函数是一种特殊的成员函数,名字和类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值,并且在对象的生命周期内只调用一次;
特性:
//日期类
class Date
{
public:
//无参构造函数,默认构造函数
Date()
{}
//带参构造函数
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Display()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1; //实例化时调用无参构造函数
d1.Display();
Date d2(2021, 10, 23); //实例化时调用带参构造函数
d2.Display();
return 0;
}
//默认构造函数只能有一个
class Date
{
public:
//无参默认构造函数
Date()
{
_year = 1921;
_month = 7;
_day = 1;
}
//全缺省默认构造函数
Date(int year = 2021, int month = 10, int day = 23)
{
_year = year;
_month = month;
_day = day;
}
void Display()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
注:C++把类型分为内置类型和自定义类型
class Time
{
public:
Time()
{
cout << "Time()" << endl;
_hour = 0;
_minute = 0;
_second = 0;
}
private:
int _hour;
int _minute;
int _second;
};
class Date
{
private:
//内置类型(基本类型)
int _year;
int _month;
int _day;
//自定义类型(类)
Time _t;
};
int main()
{
Date d; //会对自定义类型_t调用默认无参函数
return 0;
}
class Date
{
public:
Date()
{
_year = 2020;
}
private:
//默认构造函数的缺省值 C++11
int _year = 0; //2020
int _month = 1; //1
int _day = 1; //1
};
局部优先原则
//局部优先原则
class Date
{
public:
Date(int year)
{
year = year;
}
private:
int year;
};
int main()
{
Date d(1); //成员变量year还是随机值,可this->year指定
return 0;
}
二,析构函数
与构造函数相反,析构函数不是完成对象的销毁,局部对象的销毁工作是由编译器完成的;
而对象在销毁时,会自动调用析构函数,完成类的一些资源清理工作;
特性:
class SeqList
{
public:
//构造函数
SeqList(int capacity = 0)
{
_pData = (int*)malloc(capacity * sizeof(int));
assert(_pData);
_size = 0;
_capacity = capacity;
}
//析构函数
~SeqList()
{
if (_pData)
{
free(_pData);
_pData = NULL;
_capacity = 0;
_size = 0;
}
}
private:
int* _pData;
size_t _size;
size_t _capacity;
};
class String
{
public:
//构造函数
String(const char* str = "jack")
{
_str = (char*)malloc(strlen(str) + 1);
assert(_str);
strcpy(_str, str);
cout << _str << endl;
}
//析构函数
~String()
{
cout << "~String()" << endl;
free(_str);
}
private:
char* _str;
};
class Person
{
private:
String _name;
int _age;
};
int main()
{
Person P;
return 0;
}
三,拷贝构造函数
拷贝构造函数,也称复制构造函数,会拷贝复制一个同类对象;只有单个形参,该形参是对本类类型对象的引用(一般使用const修饰,但并不限),在用已存在的类类型对象创建新对象时由编译器自动调用;
特征:
class Date
{
public:
//构造函数
Date(int year = 2021, int month = 10, int day = 23)
{
_year = year;
_month = month;
_day = day;
}
//拷贝构造函数
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1); //书写形式也可未:Date d2 = d1;
return 0;
}
class Date
{
public:
//构造函数
Date(int year = 2021, int month = 10, int day = 23)
{
_year = year;
_month = month;
_day = day;
}
//不是要拷贝构造函数,使用指针也可以,但不方便
Date(Date* p)
{
_year = p->_year;
_month = p->_month;
_day = p->_day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(&d1);
return 0;
}
//无拷贝构造函数,默认生成
class Date
{
public:
//构造函数
Date(int year = 2021, int month = 10, int day = 23)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(d1); //浅拷贝或值拷贝
return 0;
}
//无拷贝构造函数,默认生成
class String
{
public:
//构造函数
String(const char* str = "jack")
{
_str = (char*)malloc(strlen(str) + 1);
assert(_str);
strcpy(_str, str);
}
//析构函数
~String()
{
cout << "~String()" << endl;
free(_str);
}
private:
char* _str;
};
int main()
{
String s1;
String s2(s1);
//无拷贝构造函数,调用默认生成的拷贝构造函数,内置类型浅拷贝;
//生命周期结束时,调用析构函数,s2释放空间后,s1又接着释放,会造成重复释放,系统会报错;
//需将浅拷贝,改为深拷贝;
return 0;
}
四,赋值运算符重载
运算符默认是给内置类型使用的,自定义类型需运算符重载,即需自己定义实现运算符行为;为了增强代码的可读性,C++引入了运算符重载,其是具有特殊函数名的函数,有返回值类型,函数名,及参数列表,其返回值类型与参数列表与普通函数类似;
注:
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//private:
int _year;
int _month;
int _day;
};
//引用成员变量,不可为private
bool operator == (const Date& d1, const Date& d2)
{
return d1._year == d2._year
&& d1._month == d2._month
&& d1._day == d2._day;
}
int main()
{
Date d1;
Date d2;
//正常调用方式为,operator==(d1,d2),但可读性很差,还不如写一个EqualDate函数
cout << (d1 == d2) << endl;
return 0;
}
class Date
{
public:
//构造函数
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//运算符重载
//bool operator == (Date* this, const Date& d2)
bool operator == (const Date& d2)
{
return _year == d2._year
&& _month == d2._month
&& _day == d2._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2;
//类似d1.operator==(d2),即编译器翻译为d1.operator==(&d1,d2)
cout << (d1 == d2) << endl;
return 0;
}
赋值运算符重载
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;
}
//赋值运算符重载,无则默认会自动生成
Date& operator = (const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(2020, 2, 2);
Date d3(2021, 3, 3);
d1 = d2 = d3;
return 0;
}
//无赋值运算符重载,默认生成
class String
{
public:
//构造函数
String(const char* str = "jack")
{
_str = (char*)malloc(strlen(str) + 1);
assert(_str);
strcpy(_str, str);
}
//析构函数
~String()
{
cout << "~String()" << endl;
free(_str);
}
private:
char* _str;
};
int main()
{
String s1("hello");
String s2("world");
s1 = s2;
//无赋值运算符重载,调用默认赋值运算符重载函数,内置类型浅拷贝;
//生命周期结束时,调用析构函数,s2释放空间后,s1又接着释放,会造成重复释放,系统会报错;
//需将浅拷贝,改为深拷贝;
return 0;
}
五,日期类的实现
各种运算符重载的实现https://gitee.com/napoleoncode/start-code/tree/master/C++/Datehttps://gitee.com/napoleoncode/start-code/tree/master/C++/Date
class Date
{
public:
//获取某年某月的天数
int GetMonthDay(int year, int month)
{
assert(month > 0 && month < 13);
static 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;
return monthDays[month];
}
//构成函数
Date(int year = 0, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
//判断合法性
if (_year < 0 || (_month <= 0 || _month >= 13) || (_day <= 0 || _day > GetMonthDay(_year, _month)))
{
cout << _year << "/" << _month << "/" << _day << "->";
cout << "非法日期" << endl;
}
}
void print()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
//运算符重载函数
//日期 += 天数
Date& operator += (int day);
//日期 -= 天数
Date& operator -= (int day);
//日期 + 天数
Date operator + (int day);
//日期 - 天数
Date operator - (int day);
//前置++
Date& operator ++ ();
//后置++
Date operator ++ (int);
//前置--
Date& operator -- ();
//后置--
Date operator -- (int);
//日期 - 日期 (返回天数)
int operator - (const Date& d);
// > 运算符重载
bool operator > (const Date& d);
// >= 运算符重载
bool operator >= (const Date& d);
// < 运算符重载
bool operator < (const Date& d);
// <= 运算符重载
bool operator <= (const Date& d);
// == 运算符重载
bool operator == (const Date& d);
// != 运算符重载
bool operator != (const Date& d);
private:
int _year;
int _month;
int _day;
};
六,const成员
const 修饰类的成员函数
注:
class Date
{
public:
//构造函数
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
//Display(Date* this)
void Display()
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
const Date d(2020, 1, 1);
//d.Display(&d)
d.Display(); //报错,因为权限放大
}
//日期类,const修饰的成员函数
class Date
{
public:
void Display()const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
//编译器翻译为
class Date
{
public:
void Display(const Date* this)
{
cout << this->_year << "/" << this->_month << "/" << this->_day << endl;
}
private:
int _year;
int _month;
int _day;
};
七,取地址及const取地址操作符重载
class Date
{
public:
//取地址操作符重载
Date* operator&()
{
return this;
}
//const取地址操作符重载
const Date* operator&() const
{
return this;
}
private:
int _year;
int _month;
int _day;
};
附
class Date
{
public:
//构造函数
Date()
{}
//拷贝构造函数
Date(const Date& d)
{
cout << "Date(Date& d)" << endl;
}
};
Date f()
{
Date d;
return d;
}
int main()
{
//d拷贝构造给临时变量,临时变量在拷贝构造给ret1,两次拷贝构造
//但编译器会优化,直接将d拷贝给ret1,一次拷贝构造
Date ret1 = f();
Date ret2;
//d拷贝构造给临时变量,临时变量在赋值重载给ret1,1次拷贝构造
ret2 = f();
return 0;
}
class Date
{
public:
//构造函数
Date()
{}
//拷贝构造函数
Date(const Date& d)
{
cout << "Date(Date& d)" << endl;
}
};
Date f(Date d)
{
return d;
}
int main()
{
//两个拷贝构造
Date ret;
f(ret);
cout << endl;
//Date()是匿名对象,生命周期只在这一行
//Date()先构造,在拷贝构造给d,但编译器优化为只有一个构造
f(Date());
return 0;
}