机票网站制作,58网站怎么做品牌推广,平台网站模板 优帮云,WordPress插件后天怎么编写目录 类的6个默认成员函数构造函数自己写的构造函数默认生成的构造函数 析构函数概念特征 拷贝构造函数特征 运算符重载 、 、 赋值重载Date类的完善构造函数的完善用复用 类的6个默认成员函数
默认成员函数#xff1a;不写编译器也会默认生成一份
构造函数
自己… 目录 类的6个默认成员函数构造函数自己写的构造函数默认生成的构造函数 析构函数概念特征 拷贝构造函数特征 运算符重载 、 、 赋值重载Date类的完善构造函数的完善用复用 类的6个默认成员函数
默认成员函数不写编译器也会默认生成一份
构造函数
自己写的构造函数
构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任 务并不是开空间创建对象而是初始化对象。 其特征如下
函数名与类名相同。无返回值不需要写void。对象实例化时编译器自动调用对应的构造函数。构造函数可以重载。. 如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦 用户显式定义编译器将不再生成。关于编译器生成的默认成员函数很多童鞋会有疑惑不实现构造函数的情况下编译器会 生成默认的构造函数。但是看起来默认构造函数又没什么用d对象调用了编译器生成的默 认构造函数但是d对象_year/_month/_day依旧是随机值。也就说在这里编译器生成的 默认构造函数并没有什么用 解答C把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类 型如int/char…自定义类型就是我们使用class/struct/union等自己定义的类型看看 下面的程序就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员 函数。无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个。 注意无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数都可以认为 是默认构造函数。
#include iostream
using namespace std;class Date
{
public:Date(){_day 1;_month 1;_year 1;}Date(int day, int month, int year){_day day;_month month;_year year;}void Print(){cout _year - _month - _day endl;}
private:int _day;int _month;int _year;
};int main()
{Date d1;Date d2(2023, 1, 24);d1.Print();d2.Print();return 0;
}对于没有参数的初始化对象时不能写成下面那样因为无法与函数声明区分 Date d1() 也可以用缺省函数下面两个函数构成函数重载但是无参调用的时候会产生歧义
//Date()
// {
// _day 1;
// _month 1;
// _year 1;
// }Date(int day 1, int month 1, int year 1){_day day;_month month;_year year;}默认生成的构造函数
默认构造函数编译器默认生成的、无参的构造函数、全缺省的构造函数可以不传参的都叫默认构造这三个函数不能同时存在因为会存在调用歧义。 如果不写构造函数有没有构造函数 默认生成的但此时是随机值
class Date
{
public:void Print(){cout _year - _month - _day endl;}
private:int _day;int _month;int _year;
};int main()
{Date d1;d1.Print();return 0;
}对于栈的初始函数来说初始化的也是随机值
class Stack
{
public:private:int* _a;int _top;int _capacity;
};int main()
{Stack s1;return 0;
}但对于像MyQueue的构造函数就初始化了 规则 内置类型int/double/…指针egDate* p是内置类型 自定义类型 class struct… 默认生成的构造函数对于内置类型成员不做处理看编译器建议当成不处理自定义类型会取调用它的默认构造调用无参的默认构造如果自定义类型没有默认构造 - 初始化列表类和对象下讲 对于这个缺陷C11提供如下解决方法下面这个写法还是声明给的缺省值
析构函数
概念
析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。
特征
析构函数是特殊的成员函数其特征如下
析构函数名是在类名前加上字符 ~。无参数无返回值类型。一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数。注意析构 函数不能重载对象生命周期结束时C编译系统系统自动调用析构函数。编译器生成的默认析构函数对自定类型成员调用它的析构函数。如果类中没有申请资源时析构函数可以不写直接使用编译器生成的默认析构函数比如 Date类有资源申请时一定要写否则会造成资源泄漏比如Stack类 日期类不需要写析构栈需要写析构
class Date
{
public:Date(int day 1, int month 1, int year 1){_day day;_month month;_year year;}void Print(){cout _year - _month - _day endl;}~Date(){cout ~Date() endl;}
private:int _day 1;int _month 1;int _year 1;
};int main()
{Date d1;d1.Print();return 0;
}拷贝构造函数 浅拷贝时st和st1对象会导致对同一块空间的重复释放 解决方法自定义类型对象拷贝时调用一个函数这个函数就叫拷贝构造 - 深拷贝。 1传参的时候 2初始化构造的时候Date d2(d1)
特征
拷贝构造函数是构造函数的一个重载形式。拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错 因为会引发无穷递归调用。.0默认生成的拷贝构造函数对内置类型会完成值拷贝自定义对象回去调用它的拷贝对象。 像下面所示st1与st中的_a是指向同一块空间当这两个对象被释放时会对_a所指的这段空间释放两次从而造成错误拷贝构造主要是解决这个问题的– 深拷贝。
class Stack
{
public:Stack(){//...}Stack(const Stack stt){_a (int*)malloc(sizeof(int) * stt._capacity);if (_a nullptr){perror(malloc fail);exit(-1);}memcpy(_a, stt._a, sizeof(int) * stt._top);_top stt._top;_capacity stt._capacity;}~Stack(){cout ~Stack() endl;}
private:int* _a;int _top;int _capacity;
};1、被拷贝的对象前面加const防止意外的改变 运算符重载
对于、-、*、/、、等等内置类型可以直接使用自定义类型无法使用 解决方法1写一个函数 2使用运算符重载 运算符重载operator运算符 使用方法直接使用运算符 函数重载允许参数不同的同名函数存在 运算符重载自定义类型可以直接使用运算符 、 、
class Date
{
public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}public:int _year;int _month;int _day;
};
bool operator(Date x, Date y)
{return x._year y._year x._month y._month x._day y._day;
}
bool operator(Date x, Date y)
{if (x._year y._year)return true;else if (x._year y._year x._month y._month)return true;else if (x._year y._year x._month y._month x._day y._day)return true;return false;
}
bool operator(Date x, Date y)
{return ~(x y);
}int main()
{Date d1(2001, 3, 29);Date d2(2024, 3, 1);cout (d1 d2) endl;cout (d1 d2) endl;cout (d1 d2) endl;return 0;
}报错的原因因为流提取运算符的优先级大于因此加个括号就没事了 **此时程序的缺陷 1、运算符重载函数的参数那调用了拷贝构造 -- 用 2、为了在函数里访问类的成员变量把成员变量设置 成了公有 -- 在类里面设置一些访问成员的函数将运算符重载函数放到类里面 ** 缺陷1修改
bool operator(const Date x, const Date y)
{return x._year y._year x._month y._month x._day y._day;
}
bool operator(const Date x, const Date y)
{if (x._year y._year)return true;else if (x._year y._year x._month y._month)return true;else if (x._year y._year x._month y._month x._day y._day)return true;return false;
}
bool operator(const Date x, const Date y)
{return ~(x y);
}缺陷2修改
class Date
{
public:Date(int year 1, int month 1, int day 1){_year year;_month month;_day day;}bool operator(const Date y){return _year y._year _month y._month _day y._day;}bool operator(const Date y){if (_year y._year)return true;else if (_year y._year _month y._month)return true;else if (_year y._year _month y._month _day y._day)return true;return false;}bool operator(const Date y){return ~(*this y);}private:int _year;int _month;int _day;
};也可以d1.operator(d2)这样显示的调用 这个类还可以些哪些运算符重载这个取决于哪些运算符对于这个类是有意义的 eg日期-日期、日期天数、日期天数 int GetMonthDay(int year, int month){assert(year 1 month 1 day 1);int arr[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 arr[month];}Date operator(int day){_day day;while (_day GetMonthDay()){_day - GetMonthDay();_month;if (_month 12){_year;_month 1;}}return *this;}细节 根据内置类型的定义是有返回值的因此自定义类型也应该有返回值 int GetMonthDay(int year, int month){assert(year 1 month 1 day 1);int arr[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 arr[month];}
Date operator(int day){Date tmp(*this);tmp._day day;while (tmp._day GetMonthDay(tmp._year, tmp._month)){tmp._day - GetMonthDay(tmp._year, tmp._month);tmp._month;if (tmp._month 12){tmp._year;tmp._month 1;}}return tmp;}赋值重载
operator 我们不写编译器回生成默认的operator。跟拷贝构造的行为类似内置类型值拷贝自定义类型调用他的赋值 Date、MyQueue可以不用写默认生成的operator就可以用 赋值重载重载运算符两个已经存在的对象拷贝 拷贝构造一个已经存在的对象去拷贝初始化另一个对象 缺省参数不能同时出现在声明与定义里面只能在声明中定义 Date operator(const Date y);Date Date::operator(const Date y)
{if (this ! y){_year y._year;_month y._month;_day y._day;}return *this;
}Date类的完善
构造函数的完善
Date::Date(int year 1, int month 1, int day 1)
{_year year;_month month;_day day;if (_year 1 || _month 13 || _month 1 || day 1 || day GetMonthDay(_year, _month)){print();cout 日期非法 endl;}
}用复用
复用1
Date Date::operator(int day)
{*this *this day;return *this;}
Date Date::operator(int day)
{Date tmp(*this);tmp._day day;while (tmp._day GetMonthDay(tmp._year, tmp._month)){tmp._day - GetMonthDay(tmp._year, tmp._month);tmp._month;if (tmp._month 12){tmp._year;tmp._month 1;}}return tmp;}复用2
Date Date::operator(int day)
{_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 12){_year;_month 1;}}return *this;}
Date Date::operator(int day)
{Date tmp(*this);tmp day;return tmp;}复用2要比复用1效率更高