python怎么做视频网站,自己可以做网站吗,新产品开发流程和步骤,郑州市多商家网站制作公司#x1f511;#x1f511;博客主页#xff1a;阿客不是客 #x1f353;#x1f353;系列专栏#xff1a;从C语言到C语言的渐深学习 欢迎来到泊舟小课堂 #x1f618;博客制作不易欢迎各位#x1f44d;点赞⭐收藏➕关注 一、默认成员函数
如果一个类中什么成员都没有博客主页阿客不是客 系列专栏从C语言到C语言的渐深学习 欢迎来到泊舟小课堂 博客制作不易欢迎各位点赞⭐收藏➕关注 一、默认成员函数
如果一个类中什么成员都没有我们称之为 空类 。但是空类中真的什么都没有吗答案是否定的
类有六个默认成员函数默认成员函数就是⽤⼾没有显式实现编译器会⾃动⽣成的成员函数称为默认成员函数。 默认成员函数很重要也⽐较复杂我们要从两个⽅去学习
我们不写时编译器默认⽣成的函数⾏为是什么是否满⾜我们的需求。编译器默认⽣成的函数不满⾜我们的需求我们需要⾃⼰实现那么如何⾃⼰实现
二、构造函数
2.1 为什么要有构造函数
为了能够更好地讲解我们来写一个简单的日期类通过日期类来讲解
#include iostream
using namespace std;class Date {
public:void SetDate(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout _year / _month / _day endl;}private:int _year;int _month;int _day;
};int main(void)
{Date d1;d1.SetDate(2022, 3, 8);d1.Print();Date d2;d2.SetDate(2022, 3, 12);d2.Print();return 0;
}
对于 Date 类我们可以通过我们写的成员函数 SetDate 给对象设置内容。但是每次创建对象都要调用这个 SetDate 是不是感觉太麻烦了 ❓ 那有没有什么办法能在创建对象时自动将我们要传递的内容放置进去呢 那就要用到我们构造函数了
2.2 定义 构造函数是一个特殊的成员函数名字与类名相同, 创建类类型对象时由编译器自动调用以保证每个数据成员都有 一个合适的初始值对象实例化时初始化对象并且在对象整个生命周期内只调用一次。其特点如下 函数名与类名相同。无返回值。对象实例化时编译器自动调用对应的构造函数。构造函数可以重载。 构造函数是特殊的成员函数主要任务是初始化而不是开空间虽然构造函数的名字叫构造
2.3 构造函数的使用
构造函数的功能就相当于我们之前书写的初始化函数Init但由于其自动调用的特性大大提升了代码的容错率。
构造函数分为三种不带参数的带参数的全缺省的
我们先来看看前两种的运行结果
#includeiostream
using namespace std;class Date
{
public:// 1.⽆参构造函数Date(){_year 1;_month 1;_day 1;}// 2. 带参数构造函数Date(int year, int month, int day){_year year;_month month;_day day;}// 3.全缺省构造函数//Date(int year 1, int month 1, int day 1)//{// _year year;// _month month;// _day day;//}void print(){cout _year / _month / _day endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;//不带参数构造d1.print();Date d2(2024,10,11);//带参数构造d2.print();return 0;
} 解读不给参数时就会调用 无参构造函数给参数则会调用 带参构造函数。
用起来很简单但也有很多需要注意的地方 注意事项
构造函数是特殊的不是常规的成员函数不能直接调 d1.date() 如果通过无参构造函数创建对象对象后面不用跟括号否则就成了函数声明。 2.4 默认构造函数
如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不再生成。
那什么是默认构造有的同学会误以为不定义构造函数系统自己生成的就叫默认构造其实不然 无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数都可以认为是默认构造函数这三个函数有且只有⼀个存在不能同时存在。 总结不传实参就可以调⽤的构造就叫默认构造 注意事项
全缺省和无参的不能同时使用虽然构成函数重载但会造成调用歧义。 解读无参的构造函数和全缺省的构造函数都成为默认构造函数并且默认构造参数只能有一个虽然语法上允许它们们两个可以同时存在但是如果有对象定义去调用就会报错。 并且同时有了全缺省的构造函数就不需要使用带参数的和不带参数的构造函数强烈推荐实现全缺省或者半缺省因为真的很好用 2.5 默认构造函数的特性
通过刚才的讲解我们知道如果你没有自己定义构造函数C 编译器会自动生成一个无参的默认构造函数。当然如果你自己定义了编译器就不会帮你生成了。
那我们就让编译器自己生成一个试试
#includeiostream
using namespace std;class Date
{
public:void print(){cout _year / _month / _day endl;}private:int _year;int _month;int _day;
};int main()
{Date d1; // 这里调用的是默认生成的无参的构造函数d1.print();return 0;
} 在我们不是先构造函数的情况下编译器生成的默认构造函数。 似乎这看起来没有什么鸟用啊这不就是一堆随机值嘛…… d1 对象调用了编译器生成的默认函数但 d1 对象 year / month / day 依旧是随机值 解答C 把类型分成内置类型基本类型和自定义类型。 内置类型就是语法已经定义好的类型如 int / char...自定义类型就是我们使用 class / struct / union / stack 自己定义的类型。
C 规定我们不写编译器默认生成构造函数对于内置类型的成员变量不做初始化处理。
class A
{
public:A(){cout hello endl;}
private:int _a;
};class Date
{
public:void Print(){cout _year / _month / _day endl;}
private:A b;int _year;int _month;int _day;
};
int main()
{Date d;d.Print();return 0;
}上图中编译器对于class 类型的 b 进行了初始化自定义类型class b 的初始化就是调用 b 的构造函数而对于内置类型就没有进行初始化
而如果自定义类型 b 没有默认构造函数就会报错 你要写就写好了要么就别写不写我默认生成的能保底 三、析构函数
通过前面构造函数的学习我们知道了一个对象是怎么来的
那一个对象又是怎么没的呢既然构造函数的本质是初始化那清理的工作交给谁来干呢那就要交给析构函数了。
3.1 定义 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象是存在栈帧的函数结束栈帧销毁。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作类似我们之前Stack实现的Destroy功能。其特点与构造函数类似如下 析构函数名是在类名前加上字符 ~。无参数无返回值类型。一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数但常常不能满足我们的需要。注意析构函数不能重载对象生命周期结束时C编译系统系统自动调用析构函数。 3.2 析构函数的使用
我们知道了如果没写析构函数编译器会自动生成一个。那默认生成的析构函数会做什么事情呢它会帮我们 destroy 嘛 哪有这种好事不能什么都帮你做啊
我们刚才在构造函数中讲了 如果不自己写构造函数让编译器自动生成那么这个自动生成的 默认构造函数
对于 内置类型 的成员变量不会做初始化处理。对于 自定义类型 的成员变量会调用它的默认构造函数不用参数就可以调的初始化如果没有默认构造函数不用参数就可以调用的构造函数就会报错
而我们的析构函数也是这样的也与之类似 如果我们不自己写析构函数让编译器自动生成那么这个 默认析构函数 对于 内置类型 的成员变量不作处理 (不会帮你清理的.)对于 自定义类型 的成员变量会调用它对应的析构函数 (虽然大多数时候并没有什么用但已经仁至义尽了) 。 编译器哈哈哈给你默认生成个用用就不错了你都懒得写了不要挑三拣四滴
难道就不能帮我把这些事都干了吗帮我都销毁掉不就好了不不不举个最简单的例子迭代器析构的时候是不释放的因为不需要他来管所以默认不对内置类型处理是正常的万一误杀了怎么办对吧。
有人可能又要说了这么一来默认生成的析构函数不就没有用了吗
有用他对内置类型的成员类型不作处理会在一些情况下非常的有用比如说 两个栈实现一个队列用 C 可以非常的爽。
typedef int STDataType;
class Stack
{
public:Stack(int n 4){_a (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr _a){perror(malloc申请空间失败);return;}_capacity n;_top 0;}~Stack(){cout ~Stack() endl;free(_a);_a nullptr;_top _capacity 0;}private:STDataType* _a;size_t _capacity;size_t _top;
};// 两个Stack实现队列
class MyQueue
{
public://自动调用构造函数和析构函数private:Stack pushst;Stack popst;
};注意⼀个局部域的多个对象C规定后定义的先析构参考上述代码即先析构 _top 后析构 _capacity与栈的规则类似栈先进后出。
需要注意的是我们显⽰写析构函数对于⾃定义类型成员也会调⽤他的析构也就是说⾃定义类型成员下列代码中的Stack无论什么情况哪怕对MyQueue进行析构都会自动调用析构函数~Stack防止造成严重的内存泄漏问题。至于其他资源比如指针STDataType* _a等需要我们自己进行释放在~Stack中写的free。 如果类中没有申请资源时析构函数可以不写直接使⽤编译器⽣成的默认析构函数如Date如果默认⽣成的析构就可以⽤也就不需要显⽰写析构如MyQueue但是有资源申请时⼀定要自己写析构否则会造成资源泄漏如Stack。 四、拷贝构造
4.1 定义 我们在创建对象的时候能不能创建一个与某一个对象一模一样的新对象呢当然可以这时我们就可以用拷贝构造函数。 拷贝构造函数拷贝构造函数是构造函数的一种重载形式它可以用来创建一个与已存在的对象一模一样的新对象。对于拷贝构造它只有单个形参且该形参必须是对本类类型对象的引用因为要引用所以一般要加const修饰 拷贝构造也是一个特殊的成员函数所以他符合构造函数的一些特性 拷贝构造函数是构造函数的一个重载形式。函数名和类名相同没有返回值。若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按 字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。 拷贝构造函数的参数只有一个并且 必须要使用引用传参。 使用传值方式会引发无穷递归调用 拷贝构造函数的引用是必不可少的
4.2 拷贝构造的使用
拷贝构造的代码示例如下
class Date {
public:Date(int year 0, int month 1, int day 1) {_year year;_month month;_day day;}/* Date d2(d1); */Date(const Date d) // 这里要用引用否则就会无穷递归下去{ _year d._year;_month d._month;_day d._day;}void Print(){cout _year / _month / _day endl;}private:int _year;int _month;int _day;
};int main(void)
{Date d1(2022, 3, 9);Date d2(d1); // 拷贝复制//Date d2 d1; 和 Date d2(d1); 的效果是一样的// 看看拷贝成功没d1.Print();d2.Print();return 0;
} 其中 Date d2(d1); 和 Date d2 d1; 达成的效果是完全一样的可以选择自己喜欢的写法
4.3 为什么要使用引用传参
❓ 拷贝构造的时候直接使用 Date d 来传值传参可以吗
编译器会直接报错 但这是为什么呢
调用拷贝构造需要传值传参传值传参需要调用拷贝构造。
调用拷贝构造需要传值传参传值传参需要调用拷贝构造。
调用拷贝构造需要传值传参传值传参需要调用拷贝构造。
……
一直在传参这里出不去了一直在进行自己调用自己所以这里是一个无穷递归。 如上图所示执行date d2(d1); d1传参给拷贝构造的形参d即需要调用类A的拷贝构造函数时需要以值方式传进一个A的对象作为实参那么现在的对象只有d1了所以会出现 date d(d1)而拷贝的过程中又会调用自身的拷贝构造函数传值方式会继续传进一个A的对象作为实参会无休止的递归下去。 而加上引用则形参d是d1的别名就不需要继续进行拷贝构造。 ❓ 拷贝构造函数加 const如果函数内不需要改变建议把 const 也给它加上
万一你不小心写反了怎么办
/* Date d2(d1); */
Date(Date d) {d._year _year;d._month _month;d._day _day;
}
这样会产生一个很诡异的问题这一个可以被编译出来的 BUG 结果会变为随机值。所以这里加一个 const 就安全多了这些错误就会被检查出来了。
4.4 默认生成的拷贝构造 默认生成拷贝构造 内置类型的成员会完成按字节序的拷贝把每个字节依次拷贝过去也叫做浅拷贝。自定义类型成员会再调用它的拷贝构造。 #includeiostream
using namespace std;class Date {public:Date(int year 0, int month 1, int day 1) {_year year;_month month;_day day;}// Date(Date d) {// _year d._year;// _month d._month;// _day d._day;// }void Print() {printf(%d-%d-%d\n, _year, _month, _day);} private:int _year;int _month;int _day;
};int main(void)
{Date d1(2002, 4, 8);// 拷贝复制Date d2(d1);// 没有写拷贝构造但是也拷贝成功了d1.Print();d2.Print();return 0;
} 他这和之前几个不同了这个他还真给我解决了。
所以为什么要写拷贝构造写他有什么意义没有什么意义。
默认生成的一般情况下就够用了当然这并不意味着我们都不用写了有些情况还是不可避免要写的来查看如下代码
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 10){_array (DataType*)malloc(capacity * sizeof(DataType));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}void Push(const DataType data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);//默认拷贝构造return 0;
}这段程序会发生崩溃让我们来调试以下看看什么情况 我们会发现s1和s2的成员变量_array都指向同一块空间也就说编译器调用系统生成的默认构造时把s1._array指向的地址也拷贝给了s2._array这看起来没什么等到程序结束完成时调用析构函数会出现大问题 程序即将结束时调用析构函数会先析构s2第一次析构完成后s2._array指向的空间会被释放其他置为0也就是等价于s1._array指向的空间也被释放同一块空间此时再执行s1的析构函数时导致他们指向的空间被析构两次导致程序崩溃然而问题不止这些……
其实这里的字节序拷贝是浅拷贝下面几章我会详细讲一下深浅拷贝这里的深拷贝和浅拷贝先做一个大概的了解。 总结对于常见的类比如日期类默认生成的拷贝构造能用。但是对于自定义类型中需要资源申请时都需要手动写拷贝构造默认生成的拷贝构造不能用。 五、赋值运算符重载
5.1 运算符重载
5.1.1 运算符重载的定义
C为了增强代码的可读性引入了运算符重载那么什么是运算符重载呢
运算符重载是由运算符 operator 定义具有特殊函数名的函数也具有返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。简单来说就是能让自定义类型和内置类型一样使用运算符。5.1.2 运算符重载的注意事项
① 不能通过连接其他符号来创建新的操作符 你只能对已有的运算符进行重载你也不能对内置类型进行重载。 operator ❌ ② 重载操作符必须有一个类类型的操作数。
③ 用于内置类型的操作符其含义不能改变。比如内置的 整型 你不能改变其含义。
④ 作为类成员的重载函数时其形参看起来比操作数数目少 1成员函数的操作符有一个默认的形参 this限定为第一个形参。
5.1.2 重载函数的使用 代码演示运算符重载 下面实现了简单判断日期是否相当的运算符重载
class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}void print(){cout _year / _month / _day endl;}//private:int _year;int _month;int _day;
};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(2024, 1, 1);Date d2(2024, 1, 1);if (d1 d2)//也可以显示调用operator(d1,d2);{cout 日期相等 endl;}else{cout 日期不相等 endl;}return 0;
}
这里会发现运算符重载成全局的不得不将成员变量是共有的得把 private 撤掉 但这种情况下会导致我们想要私有化的内容公开出来
5.1.3 如何保证封装性
❓ 那么问题来了封装性如何保证这里其实可以用 友元 来解决
当然我们现在还没有学习到 友元可以通过将 operator 重载成成员函数来解决
class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}void print(){cout _year / _month / _day endl;}bool operator(const Date d){return _year d._year _month d._month _day d._day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 1, 1);Date d2(2024, 1, 1);if (d1 d2)//也可以显示调用operator(d1,d2);{cout 日期相等 endl;}else{cout 日期不相等 endl;}return 0;
}
5.1.4 不支持重载的运算符
注意有五个运算符不支持重载慎之慎之
. (点运算符):: (域运算符).* (点星运算符,)?: (条件运算符)sizeof
值得一提的是虽然点运算符 . 不能重载但是箭头运算符 - 是支持重载的解引用 * 是可以重载的不能重载的是点星运算符 .* 网络上不知名的冲浪大神发明的个人感觉挺不错。 5.2 赋值运算符重载
5.2.1 定义
赋值运算符重载是将运算符 进行运算符重载。但是它相较于其他运算符重载有着自己独特的特点。
需要注意的是赋值运算符重载也是默认成员函数。
作为默认成员函数的 operator 有着如下特点 参数类型const T 传递引用可以提高传参效率。返回值类型T 返回引用可以提高返回的效率支持连续赋值。检测是否自己给自己赋值。返回* this 要复合连续赋值的值。 5.2.2 赋值运算符重载的使用
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day 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(void)
{Date d1(2022, 3, 10);Date d2(2022, 7, 1);d1 d2;return 0;
}
5.2.3 使用引用可以有效减少拷贝
返回值为什么要用引用因为出了作用域 *this 还在所以我们可以使用引用来减少拷贝
我们先把引用返回去掉
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}Date(const Date d){cout 调用了一次拷贝构造 endl;_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(void)
{Date d1(2022, 3, 10);Date d2(2022, 7, 1);Date d3(d2); // 拷贝构造d1 d2;return 0;
} 运行结果如下 我们发现调用了两次拷贝构造函数。
我们来进行调试一下
① 第一句 调用了一次拷贝构造 是因为 Date d3(d2) 我们自己调用的。
② 第二句则出自 d1 d2
因为传值返回不会直接返回对象而是会生成一个拷贝的对象。
我们这里出了作用域对象还在就可以使用引用返回 Date operator(const Date d)//赋值运算符重载
{if (this ! d){_year d._year;_month d._month;_day d._day;}return *this;
} 成功减少了拷贝 我们也就可以得出结论 赋值传参如果不加引用会先去调用拷贝构造再进入operator进行赋值operator本身不像拷贝构造一样无穷递归但operator传参加入引用就不会先去调用拷贝构造 5.3 实践日期类的实现
我们学习了上面的知识来尝试实现一个日期类的代码吧
class Date
{
public:// 获取某年某月的天数int GetMonthDay(int year, int month);// 全缺省的构造函数Date(int year 1900, int month 1, int day 1);// 拷贝构造函数// d2(d1)Date(const Date d);// 赋值运算符重载// d2 d3 - d2.operator(d2, d3)Date operator(const Date d);// 析构函数~Date();// 日期天数Date operator(int day);// 日期天数Date operator(int day);// 日期-天数Date operator-(int day);// 日期-天数Date operator-(int day);// 前置Date operator();// 后置Date operator(int);// 后置--Date operator--(int);// 前置--Date operator--();// 运算符重载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);// 日期-日期 返回天数int operator-(const Date d);private:int _year;int _month;int _day;
};
我们获取当月日期的函数经常需要调用所以我们就将其写在定义里面。
int GetMonthDay(int year, int month)
{assert(month 0 month 13);static int monthDayArray[13] { -1, 31, 28, 31, 30, 31, 30,31, 31, 30, 31, 30, 31 };// 365天 5h if (month 2 (year % 4 0 year % 100 ! 0) || (year% 400 0)){return 29;}else{return monthDayArray[month];}
}
#includeDate.hbool Date::CheckDate()
{if (_month 1 || _month 12 || _day 1 || _day GetMonthDay(_year, _month)){return false;}else{return true;}
}// 全缺省的构造函数
Date::Date(int year, int month, int day)
{_year year;_month month;_day day;if (!CheckDate()){cout ⽇期⾮法 endl;}
}void Date::Print()
{cout _year - _month - _day endl;
}
// 拷贝构造函数
// d2(d1)
Date::Date(const Date d)
{_year d._year;_month d._month;_day d._day;
}// 赋值运算符重载
// d2 d3 - d2.operator(d2, d3)
Date Date::operator(const Date d)
{if (this ! d){_year d._year;_month d._month;_day d._day;}return *this;
}// 析构函数
Date::~Date()
{_year 0;_month 0;_day 0;
}// 日期天数
Date Date::operator(int day)
{if (day 0){return *this - -day;}_day day;while (_day GetMonthDay(_year, _month)){_day - GetMonthDay(_year, _month);_month;if (_month 13){_month 1;_year;}}return *this;
}// 日期天数
Date Date::operator(int day)
{Date tmp *this;tmp day;return tmp;
}// 日期-天数
Date Date::operator-(int day)
{Date tmp *this;tmp - day;return tmp;
}// 日期-天数
Date Date::operator-(int day)
{if (day 0){return *this -day;}_day - day;while (_day 0){_day GetMonthDay(_year, _month);_month--;if (_month 0){_month 12;_year--;}}return *this;
}// 前置
Date Date::operator()
{*this 1;return *this;
}// 后置
Date Date::operator(int)
{Date tmp *this;*this 1;return tmp;
}// 后置--
Date Date::operator--(int)
{Date tmp *this;*this - 1;return tmp;
}// 前置--
Date Date::operator--()
{*this - 1;return *this;
}// 运算符重载
bool Date::operator(const Date d)
{if (_year d._year){return true;}else if(_year d._year){if (_month d._month){return true;}else if(_month d._month){return _day d._day;}}return false;
}// 运算符重载
bool Date::operator(const Date d)
{return _year d._year _month d._month _day d._day;
}// 运算符重载
bool Date::operator (const Date d)
{return *this d || *this d;}// 运算符重载
bool Date::operator (const Date d)
{return !(*this d);
}// 运算符重载
bool Date::operator (const Date d)
{return !(*this d);return true;
}// !运算符重载
bool Date::operator ! (const Date d)
{return !(*this d);
}// 日期-日期 返回天数
int Date::operator-(const Date d)
{Date max *this;Date min d;int flag 1;if (*this d){max d;min *this;flag -1;}int n 0;while (max ! min){min;n;}return n * flag;
} 六、取地址重载
6.1 const 修饰成员函数
首先我们得知道一个规则就是const修饰的常变量不能赋值给普通变量因为这样造成const权限的放大但是普通变量可以赋值给const修饰的常变量。所以让我们来看看这段代码
class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout Print() endl;cout year: _year endl;cout month: _month endl;cout day: _day endl endl;}
private:int _year; // 年int _month; // 月int _day; // 日
};int main()
{const Date d1(2022, 1, 13);d1.Print();//errorreturn 0;
}这段代码会出错因为 d2 调用 Print 函数是将 const Date* 作为参数类型传过去而函数接受的类型是 Date* 这样就会造成权限的放大。为了解决这个问题就需要使用const修饰原函数 void Print() const{cout Print() endl;cout year: _year endl;cout month: _month endl;cout day: _day endl endl;} 6.2 取地址运算符
取地址运算符和 const取地址运算符重载也是默认成员函数
#include iostream
using namespace std;class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}Date* operator(){return this;}const Date* operator()const{return this;}private:int _year;int _month;int _day;
};
这两个运算符一般不需要重载使用编译器生成的默认取地址的重载即可只有特殊情况才需要重载比如不想让别人获取到你的地址
#include iostream
using namespace std;class Date {
public:Date(int year, int month, int day){_year year;_month month;_day day;}Date* operator(){// return this; 我不想让你取我的地址return nullptr;}private:int _year;int _month;int _day;
};int main(void)
{Date d1(2022, 2, 2);cout d1 endl;return 0;
}
或者这样
Date* operator() {// return this; 我想误导你return 0xFE087460;}
返回一个看似正常的地址让你的同学调用你的库的时候摸不着头脑但需要慎用