东莞手机网站建设,怎么用手机创建网站,wordpress网站系统,firework做网站教程目录1.类的6个默认成员函数2.构造函数2.1概念2.2特性3.析构函数3.1概念3.2特性4.拷贝构造函数4.1概念4.2特征5.赋值运算符重载5.1运算符重载5.2赋值运算符重载5.3前置和后置重载5.4流插入和流提取运算符重载6.const成员7.取地址重载和const取地址操作符重载1.类的6个默认成员函…
目录1.类的6个默认成员函数2.构造函数2.1概念2.2特性3.析构函数3.1概念3.2特性4.拷贝构造函数4.1概念4.2特征5.赋值运算符重载5.1运算符重载5.2赋值运算符重载5.3前置和后置重载5.4流插入和流提取运算符重载6.const成员7.取地址重载和const取地址操作符重载1.类的6个默认成员函数 默认成员函数用户没有显示实现编译器会生成的成员函数称为默认成员函数。 如果一个类中什么成员都没有简称为空类。
但空类中真的是什么都没有吗并不是的任何一个类在我们不写的情况下都会自动生成下面6个默认成员函数。
class Date{};构造函数 完成初始化工作析构函数 完成清理工作拷贝构造函数 使用同类对象初始化创建对象赋值重载 把一个对象赋值给另一个对象取地址操作符重载 对普通对象取地址const取地址操作符重载 对const修饰的对象取地址 2.构造函数
2.1概念
对于下面的Date类
class Date
{
public:void Init(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()
{Date today1;today1.Init(2023,1,16);today1.Print();Date today2;today2.Init(2023, 1, 17);today2.Print();return 0;
}对于Date类可以通过Init公有方法给对象设置日期但如果每次创建对象时都调用该方法设置信息未免有点麻烦那能否在对象创建时就将信息设置进去呢
我们就需要一个函数保证对象被创造出来就被初始化了。
C的构造函数提供了这个功能 构造函数是一个特殊的成员函数名字与类名相同创建类类型对象时由编译器自动调用以保证每个数据成员都有一个合适的初始值并且在对象整个生命周期内只调用一次。 2.2特性
构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任务并不是开空间创建对象而是初始化对象。
其特征如下 函数名与类名相同。 无返回值也不用写void 对象实例化时编译器自动调用对应的构造函数。 构造函数可以重载。一个类可以有多个构造函数 class Date
{
public:Date(){cout 自定义默认构造函数 endl;}//Date(int year 1, int month 2, int day 3)//{// cout 自定义全缺省默认构造函数 endl;//}//Date(int year, int month, int day 1)//{// cout 自定义半缺省构造函数 endl;//}Date(int year, int month, int day){cout 自定义构造函数 endl;}
private:int _year;int _month;int _day;
};int main()
{Date today(2023, 2, 6);return 0;
}无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数一个类中只能有一个。 原因: 这两个构造函数虽然满足重载但编译器无法调用存在歧义。如上面代码的第一个无参构造函数和第二个注释的全缺省的构造函数所以默认构造函数一个类只能有一个。非默认构造函数也只能有一个如第三个半缺省构造函数和第四个构造函数需要传参同时存在会有歧义 注意 更具构造函数需不需要传参数我们将其分为两种 默认构造函数 无参构造函数、全缺省构造函数我们没写编译器默认生成的构造函数下一条这些不需要传参数的构造函数都认为是默认构造函数传参构造函数 不缺省构造函数、全缺省构造函数 创建对象时调用默认构造函数不要在对象后加括号加括号后编译器会将其看作函数的声明而不是创建的对象。调用传参的构造函数在对象后加括号加参数。 如果类没有显示定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显示定义编译器将不再生成。构造函数可以重载有很多种只要我们写一种编译器就不会默认生成构造函数 注意 如下创建对象时不带括号调用的是默认构造函数带括号后跟参数调用传参构造函数。 如下图类中已经定义了构造函数编译器不会在自动生成默认构造函数。 在增加默认构造函数后正常运行 关于编译器生成的默认构造函数很多人会疑惑不实现构造函数的情况下编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用 如下面的代码today对象调用了编译器生成的默认构造函数但是today对象的三个成员变量_day/_month/_year依然是随机数也就是说在这里编译器生成的默认构造函数并没有什么用 先介绍一点C将类型分为以下两种
内置类型 语言提供的数据类型如int、char…自定义类型 我们使用struct、class、union等自己定义的类型
如果一个类中存在自定义类型的成员变量需要使用该成员变量对应类的默认构造函数来初始化否则无法通过。这也就是默认构造函数存在的意义。 自定义类型的成员变量对应类存在默认构造函数 class A
{
public:A(){cout A endl;}
private:int a;int b;
};class Date
{
public:Date(){cout 默认构造函数 endl;}Date(int year, int month, int day){cout 传参构造函数 endl;}
private:int _year;int _month;int _day;A a1;
};int main()
{Date today;return 0;
}自定义类型的成员变量对应类不存在默认构造函数 class A
{
public:A(int c){cout A endl;}
private:int a;int b;
};class Date
{
public:Date(){cout 默认构造函数 endl;}Date(int year, int month, int day){cout 传参构造函数 endl;}
private:int _year;int _month;int _day;A a1;
};int main()
{Date today;return 0;
}注意 在C11中针对内置成员不初始化的缺陷又打了补丁即内置类型成员变量在类中声明时可以给默认值。
class A
{
public:void Print(){cout _a _b endl;}
private:int _a 10;int _b 20;
};class Date
{
public:void Print(){a1.Print();}private:int _year 2000;int _month 1;int _day 1;A a1;
};
int main()
{Date today;today.Print();return 0;
}此为缺省值当构造函数没有初始化成员变量时成员变量的值即为该缺省值若初始化以构造函数为主如下面代码初始化了一个变量该变量就以构造函数初始化为主其他成员变量为缺省值
class A
{
public:A(){_a 40;}void Print(){cout _a _b endl;}
private:int _a 10;int _b 20;
};class Date
{
public:void Print(){a1.Print();}private:int _year 2000;int _month 1;int _day 1;A a1;
};
int main()
{Date today;today.Print();return 0;
}3.析构函数
3.1概念 我们知道了对象创建时需要构造函数来初始化那对象销毁时又需要什么呢 析构函数 与构造函数相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时自动调用析构函数完成对象中资源的清理工作。
我们创建一个对象它是在对象生命周期结束后对应函数的栈帧销毁时一并销毁而析构函数是在销毁前函数自动调用对该对象的资源做清理清空对象的空间或将申请的空间还给编译器。
对于清理工作我们必须要做否则可能会造成内存泄漏而我们又常常忘记这一操作于是C增加了这么一个函数。
3.2特性 析构函数名是在类名前加上字符**~**取反符号 无参数也无返回值 一个类只能有一个析构函数。若未显示定义系统会自动生成默认的析构函数。注意析构函数不能重载 对象生命周期结束时C编译系统自动调用析构函数。 我们编写如下代码向内存申请空间利用析构函数释放对应的空间。 class Stack
{
public:Stack(){ArrStack (int*)malloc(sizeof(int) * 4);if(!ArrStack)//下图中未写{preeor(malloc fail!);exit(-1);}_size 4;_top 0;}~Stack(){if (ArrStack){free(ArrStack);ArrStack nullptr;_size 0;_top 0;}}
private:int* ArrStack;int _size;int _top;
};int main()
{Stack st;return 0;
}如果类中没有申请资源时析构函数可以不写直接使用编译器生成默认析构函数比如Date类有资源申请时一定要写否则会造成资源泄漏。
如下面的代码当我们对同一个类创建两个变量时构造函数的执行顺序为s1、s2而函数是一种栈的形式创建变量就是压栈s1先入栈s2后入栈销毁时s2先出栈s1后出栈析构函数的调用顺序为s2、s1
class Stack
{
public:Stack(int num){ArrStack (int*)malloc(sizeof(int) * num);if(!ArrStack)//下图中未写{preeor(malloc fail!);exit(-1);}_size 4;_top 0;}~Stack(){if (ArrStack){free(ArrStack);ArrStack nullptr;_size 0;_top 0;}}
private:int* ArrStack;int _size;int _top;
};int main()
{Stack s1(10);Stack s1(40);return 0;
}观察下图this-_size的变化 当一个类中有自定义类型的成员变量那再销毁这个类创建的对象时会调用该类中自定义类型的成员变量的析构函数 写析构函数 class A
{
public:~A(){cout A endl;}
private:int a;int b;
};class Date
{
public:~Date(){cout Date endl;}
private:int _year;int _month;int _day;A a1;
};
int main()
{Date today;return 0;
}不写析构函数 class A
{
public:~A(){cout A endl;}
private:int a;int b;
};class Date
{
public:private:int _year;int _month;int _day;A a1;
};
int main()
{Date today;return 0;
}注意
默认生成构造函数和默认生成析构函数对内置类型不处理处理自定义类型。有些编译器会但那时编译器的个人行为和C的语法无关
4.拷贝构造函数
4.1概念 拷贝构造函数 只有单个形参该形参是对本类类型对象的引用一般常用const修饰在用已存在的类类型对象创建新对象时由编译器自动调用。 该函数功能为将一个对象的数据赋值给另一个对象发生拷贝时编译器就会调用该函数如下
class Date
{
public:Date(int year,int month,int day){_year year;_month month;_day day;}Date(const Date d)//拷贝构造函数{_year d._year;_month d._month;_day d._day;cout 拷贝构造函数 endl;}private:int _year;int _month;int _day;
};void test(Date d)//调用拷贝构造函数
{}int main()
{Date today1(2023,2,7);Date today2(today1);//调用拷贝构造函数test(today1);return 0;
}4.2特征 拷贝构造函数是构造函数的一个重载形式。 拷贝构造函数的参数只有一个 且 必须是类类型对象的引用 使用传参方式编译器会直接报错 因为会引发无穷递归调用。 如果不使用引用代码如下 class Date
{
public:Date(const Date d)//拷贝构造函数{_year d._year;_month d._month;_day d._day;}private:int _year;int _month;int _day;
};这样的拷贝构造函数我们在调用它时会发生拷贝而需要拷贝我们就要调用拷贝构造函数这就会形参死循环因为要用你我调用你而想要调用你就要用你编译器不会允许这样的事情发生。 如上图将对象d1的数据拷贝到d2需要调用拷贝构造函数而调用的过程形参发生拷贝又要调用拷贝构造函数就这样一直下去很明显这是不行的。 所以在这里我们要使用引用如下 Date(const Date d)//拷贝构造函数{_year d._year;_month d._month;_day d._day;}在第一次调用的时候使用d给对象起别名就不用再调用其他拷贝构造函数。 对于这个函数建议使用const修饰防止我们在写这个函数时不小心写错使对象的成员变量发生改变。 **若未显示定义编译器会生成默认的拷贝构造函数。**默认的拷贝构造函数对象按内存存储按字节序完成拷贝这种拷贝叫浅拷贝或值拷贝。 即上面的Date类对象若发生浅拷贝只是将一个对象所占空间内所有成员变量的值拷贝到另一个对象的成员变量这么做看起来似乎很合理其实不然对于内置类型这么做当然没有问题但如栈这样的数据结构是万万不能的。如下面栈的代码 class Stack
{
public:Stack(size_t capacity 10){_array (int*)malloc(int* sizeof(int));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:int *_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;
}这样程序必定会发生错误。 如果想要让程序正确运行我们需要我们自己编写拷贝构造函数也就是深拷贝让他们每个对象的的成员变量在面对这种情况时都有自己独立的空间而不是共用一块空间。 这也是拷贝构造函数存在的意义编译器只能做浅拷贝的工作若果一个对象的拷贝需要使用深拷贝就需要程序员手动来完成这个任务这也是C语言存在的缺陷C的很好的弥补了这一点。 修改后的栈代码如下 class Stack
{
public:Stack(size_t capacity 10){_array (int*)malloc(capacity * sizeof(int));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}Stack(const Stack st){_array (int*)malloc(sizeof(int) * st._capacity);if (_array nullptr){perror(malloc申请空间失败);return;}for (int i 0; i st._size; i){_array[i] st._array[i];}_size st._size;}void Push(const int data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:int* _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;
}所以如果类中没有涉及资源申请时拷贝构造函数是否写都可以若涉及到资源申请时则拷贝构造函数是一定要写的否则就是浅拷贝。 拷贝构造函数调用频率最多的三种场景场景如下 使用以存在的对象创建新对象函数参数类型为类类型对象函数返回值类型为类类型对象
通过这些我们也可以看出拷贝在编写代码中是一个平常的事情但其消耗的资源却不少所以在实际使用中如果可以使用引用尽量使用引用减少计算机消耗创出更优得程序。
5.赋值运算符重载
5.1运算符重载 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数 也具有其返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 在C中类的封装性是做的很好的如果想在类和类之间进行比较拷贝等操作需要在类内调用函数而对应普通的内置类型只需要使用简单的运算符即可完成C规定可以将部分运算符重载来完成这个功能增强了代码的可读性。 函数名字为关键字operator后面接需要重载的运算符符号。
函数原型返回值类型 operator操作符(参数列表)
注意
不能通过连接其他符号来创建新的操作符比如operator重载操作符必须有一个类类型参数用于内置类型的运算符其含义不能改变例如内置的整形不能改变其含义作为类成员函数重载时其形参看起来比操作数数目少1.因为成员函数的第一个参数为隐藏的this.* :: sizeof ?: .注意以上5个运算符不能重载。在这个经常在笔试选择题中出现。
如下代码若运算符重载函数作用域为全局那类的成员变量必须为公有的这样封装性就无法保证
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}//成员变量变为公有才能使类外访问
//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;
}bool test()
{Date today1(2023, 2, 7);Date today2;return today1 today2;
}这里我们可以使用友元解决也可以将运算符重载函数放入类中我们一般将其放入类中。
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}bool operator(const Date d1){return _year d1._year _month d1._month _day d1._day;}private:int _year;int _month;int _day;
};bool test()
{Date today1(2023, 2, 7);Date today2;//today1.operator(today2)return today1 today2;
}在调用成员函数时编译器会自动将调用的对象作为this指针传递我们只要写入一个参数即可。
注意 在使用时需要注意运算符优先级如下面使用运算符重载需使用括号 cout (today1 today2) endl;运算符重载中如果有多个参数第一参数为左操作数第二个参数为右操作数以此类推。如上面的代码第一个参数为today1为左操作数由该对象调用运算符重载函数第二参数today2即为参数。
5.2赋值运算符重载 赋值运算符如果不自己实现编译器会默认生成只有赋值和取地址是这样的其它的自定义类型需要使用就要我们自己写。取地址在下面 赋值运算符重载格式
参数类型 const Typedef传递引用可以提高传参效率返回值类型 Typedef返回引用可以提高返回得效率有返回值目的是为了支持连续赋值。检测是否自己给自己赋值**返回*this**要符合连续赋值得含义
class Date
{
public:Date(int year 2000, 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;//返回*this}private:int _year;int _month;int _day;
};赋值运算符只能重载成类得成员函数不能重载成全局函数 class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}//private:int _year;int _month;int _day;
};//全局函数不能用this指针需要给两个参数
Date operator(const Date d1, const Date d2)
{if (d1 ! d2)//检测是否自己给自己赋值{d1._year d2._year;d1._month d2._month;d1._day d2._day;}return d1;//返回*this
}其中为了访问类中得成员变量将其公有化失去了封装性。这样得函数注定编译失败其中赋值运算符没有实现则编译器会在类中自己实现一个默认的赋值运算符而在调用得时候我们自己实现了一个编译器又实现了一个这就产生冲突。
所以赋值运算符重载只能是类的成员函数。 上面已经讲了如果我们没有自己写编译器会自己实现一个默认的赋值运算符重载在运行是是以值得方式逐字节拷贝。 上面得拷贝构造函数中编译器自己默认创建的拷贝构造函数也是相同的只能进行浅拷贝只能拷贝值无法为其分配内存但赋值运算符重载还是有一点不同的它初始化需要分配空间的时候会先为创建的对象分配空间之后在使用赋值运算符将分配好的空间舍弃存入其他对象的空间地址。 如下代码
// 这里会发现下面的程序会崩溃掉这里就需要我们以后讲的深拷贝去解决。
class Stack
{
public:Stack(size_t capacity 10){_array (int*)malloc(capacity * sizeof(int));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}void Push(const int data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:int* _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;s2 s1;return 0;
}我们要注意如果类中未涉及到资源管理赋值运算符是否实现都可以一旦涉及到资源管理则必须要实现。
5.3前置和后置重载
对于前置我们按照正常的运算符重载模式写即可但记得返回类型需要使用类类型将修改后的对象返回。
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}Date operator(){_year 1;return *this;}private:int _year;int _month;int _day;
};
int main()
{Date today(2023, 2, 7);Date d;d today; //d:2024.2,7 today:2024,2,7return 0;
}至于后置为了可以让两个函数实现重载规定增加一个int类型的参数作为区分。
注意前置是先后使用所以可以直接返回其修改后的对象对于后置是先使用后所以返回的应该是未修改的对象我们可以在修改原对象前对其进行拷贝然后修改原对象返回时直接返回之前拷贝的对象这样原对象即改变了使用的也是未改变的对象符合后置
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}Date operator(){Date temp(*this);_year 1;return temp;}private:int _year;int _month;int _day;
};int main()
{Date today(2023, 2, 7);Date d;d today; //d:2023,2,7 today:2024,2,7return 0;
}5.4流插入和流提取运算符重载
在C中我们输出和输入一个数据通常是通过cout、cin它们两其实就是一个类对象重载了、两个运算符所以输入、输出其实就是调用两个运算符重载函数。 如上图它们的类型分别为ostream、istream存放在iostream这个头文件中而C库内定义的东西都存放在std这个命名空间内所以我们每次开头需要写这两行代码。
对于内置类型如下
int a 10;
double b 10.0;
cout a;
cout b;通过函数重载调用不同的运算符函数将其打印。
下面我们一起来看一下这两个运算符是如何重载的。
流提取
在类中定义
class Date
{
public:Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}void operator(ostream out){//下面就是输出内置类型的值流提取调用头文件iostream内的out _year 年 _month 月 _day 日 endl;}private:int _year;int _month;int _day;
};int main()
{Date today;//第一个参数为左操作数第二个参数为右操作数由创建的对象调用类内的重载函数//today.operator(cout)today cout;return 0;
}我们看到函数的使用形式是today cout;类对象抢占第一个参数一定在左边cout在右边这么写肯定不符合我们平常的习惯如果要将cout放在第一个位置我们需要将函数在全局定义。
class Date
{
public:friend ostream operator(ostream out, const Date d);Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}private:int _year;int _month;int _day;
};//不对对象的成员变量做修改最好使用const修饰防止写错发生错误
ostream operator(ostream out,const Date d)
{out d._year 年 d._month 月 d._day 日 endl;return out;
}int main()
{Date today;cout today;return 0;
}如上面的代码我们函数变为全局后很好的解决了位置的问题但我们又无法访问类中的成员变量这里有三种方法我们使用第一种
使该函数变为类的友元函数在类中public作用域下使用friend修饰函数的声明即可在该函数内使用对应类的对象调用成员变量。增加接口在类中创建输出函数调用对应函数即可得到对应的成员变量值对象在类外无法访问成员变量但可以访问对外开发的函数。java喜欢这么做删除private作用域这样成员变量就可以访问。不建议这么做破坏封装性
为了防止出现下面的情况以此要输出多个对象的值我们需要使重载的函数返回cout使函数可以正常运行。
cout d1 d2 d3 endl;
//cout d1 //调用重载函数调用后返回cout继续执行
//cout d2 //同时运行后返回cout
//..
//cout endl; //与重载的类型不匹配调用头文件内的函数流插入
class Date
{
public:friend ostream operator(ostream out, const Date d);friend istream operator(istream in, Date d);Date(int year 2000, int month 1, int day 1){_year year;_month month;_day day;}private:int _year;int _month;int _day;
};ostream operator(ostream out, const Date d)
{out d._year 年 d._month 月 d._day 日 endl;return out;
}//需要改变对象的成员变量不能使用const修饰
istream operator(istream in, Date d)
{in d._year d._month d._day;return in;
}int main()
{Date today;cin today;cout today;return 0;
}如上面的代码与流提取相似。
6.const成员
如下面的代码是否可以正常运行呢
class Date
{
public:Date(int year2000,int month 1,int day 1){_year year;_month month;_day day;}void Print(){cout Print endl;}
private:int _year;int _month;int _day;
};int main()
{const Date d;d.Print();return 0;
}它不能正常运行因为对象d使用const修饰了它的值是无法改的该对象的成员变量无法修改。在调用成员函数时编译器默认传过去的值为Date* const thisthis指针表示对象本身意味着在此函数内成员变量可以改变这产生了冲突。更简单的说这就是将原本只能读的对象变成可读可写无视其权限。
想要解决这个问题只要使用const修饰*this使其无法改变即可而this又是编译器默认的它是被隐藏着的不好修改C给出了如下方法在成员函数的括号后直接加const即表示修饰*this如下 void Print() const{cout Print endl;}如果我们使用为被修饰的const对象调用被const修饰的成员函数这时可以的原本对象就可以通过调用成员函数修改和读取现在只是传过去只能使成员函数读取这没有问题。
class Date
{
public:Date(int year2000,int month 1,int day 1){_year year;_month month;_day day;}void Print() const{cout Print endl;}
private:int _year;int _month;int _day;
};int main()
{Date d;d.Print();return 0;
}同理在类中成员函数是可以相互调用的但被const修饰的成员函数无法调用没有被修饰的因为被修饰的成员函数所函数*this指针是无法改变的而没有被修饰的是可以改变的const失去了作用这种写法是错误的。而没有被修饰的成员函数是可以调用被修饰的这属于即可读又可写的情况向只可读的情况发展没有改变语法。
注意 类内部不改变成员变量的成员函数最好加上const防止数据被修改 一般会在下面的场景用到const成员 class Date
{
public:Date(int year2000,int month 1,int day 1){_year year;_month month;_day day;}void Print() const{cout _year endl;}
private:int _year;int _month;int _day;
};void test(const Date d)
{d.Print();
}int main()
{Date td;test(td);return 0;
}我们在创建对象之初一般不为其修饰cosnt但我们会经常将对象作为实参传递给其他函数如果形参被const修饰那在这个函数内它只能被读无法修改意味着调用的成员函数也必须被const修饰。 const这种写法只针对成员函数 若定义和声明分离需要修饰const时定义和声明都要修饰 成员函数被const修饰和不被修饰构成const重载 void Print() const{cout _year endl;}void Print(){cout _year endl;}一个形参为Date* const this一个为const Date* const this形参不同满足重载 若是成员函数被const修饰注意它的返回值类型若返回的是成员变量也需要修饰const否则权限发生变化编译会出错
7.取地址重载和const取地址操作符重载
取地址重载和const取地址操作符重载是最后两个编译器默认生成的成员函数我们一般不会去写它而是直接去使用编译器默认生成的。
class Date
{
public:Date(int year2000,int month 1,int day 1){_year year;_month month;_day day;}
private:int _year;int _month;int _day;
};int main()
{Date d1;const Date d2;cout d1 endl;cout d2 endl;return 0;
}我们如果想要写出来也可以如下
class Date
{
public:Date(int year2000,int month 1,int day 1){_year year;_month month;_day day;}Date* operator()//取地址重载{return this;}const Date* operator() const //const取地址操作符重载{return this;}
private:int _year;int _month;int _day;
};int main()
{Date d1;const Date d2;cout d1 endl;cout d2 endl;return 0;
}两个使用的场景不同取地址重载用在取一般的对象的地址const取地址操作符重载用在取被const修饰的对象的地址。