泰安网站建设哪里找,情人节网页 wordpress,天津网站制作专业,辽宁省建设工程信息网a类业绩目录
一、 运算符重载
函数重载和运算符重载有什么关系#xff1f;
二、.*运算符的作用
三、运算符重载的正常使用
四、重载成成员函数
五、赋值运算符重载
1.赋值运算符重载格式
传值返回和引用返回
有没有办法不生成拷贝#xff1f;
2. 赋值运算符只能重载成类的…目录
一、 运算符重载
函数重载和运算符重载有什么关系
二、.*运算符的作用
三、运算符重载的正常使用
四、重载成成员函数
五、赋值运算符重载
1.赋值运算符重载格式
传值返回和引用返回
有没有办法不生成拷贝
2. 赋值运算符只能重载成类的成员函数不能重载成全局函数
3. 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。
六、前置和后置重载 一、 运算符重载
C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 函数名字为关键字operator后面接需要重载的运算符符号。 函数原型返回值类型 operator操作符(参数列表)。 注意
不能通过连接其他符号来创建新的操作符比如operator 重载操作符必须有一个类类型参数 用于内置类型的运算符其含义不能改变例如内置的整型不能改变其含义 作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐藏的this.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。 函数重载和运算符重载有什么关系
他们之间各论各的没有关系
运算符重载让自定义类型可以使用运算符并且控制运算符的行为增强可读性
函数重载可以让函数名相同参数不同的函数存在。
多个同一运算符的重载可以构成函数重载 二、.*运算符的作用
class OB
{
public:void func(){cout void func() endl;}
};typedef void(OB::* Ptrfunc)();// 成员函数指针类型int main()
{// 函数指针void (*ptr)();Ptrfunc fp OB::func;// 定义成员函数指针p指向函数func// 成员函数规定要加才能取到函数指针OB temp;// 定义ob类对象temp(temp.*fp)();// 调用成员函数return 0;
}typedef void(OB::* Ptrfunc)(); // 成员函数指针类型
使用 typedef 定义了一个名为 Ptrfunc 的类型这个类型是指向OB类中无参数、无返回值的成员函数的指针类型。OB::*的含义它表示这是一个指向OB类成员函数的指针 Ptrfunc。
Ptrfunc fp OB::func; // 定义成员函数指针fp指向函数func
在C中成员函数与普通函数在内存中的表示和存储方式有所不同。成员函数不仅包含函数的代码还隐含地包含了一个指向类对象的this指针这使得成员函数能够访问和修改对象的状态。在语法上类名::成员函数名是用来获取成员函数地址的标准方式如果不使用运算符编译器可能会将OB::func解析为对成员函数的调用运算符在这里的作用是明确告诉编译器“我要的是这个成员函数的地址而不是执行这个函数”。这样编译器就能正确地生成获取成员函数地址的代码而不是尝试调用该函数。
(temp.*fp)(); // 调用成员函数
.*这是一个特殊的成员访问运算符用于通过对象实例和成员函数指针来调用成员函数。当你有一个指向成员函数的指针并且想要在某个特定的对象上调用这个函数时就需要使用这个运算符。 在temp对象上通过成员函数指针fp来调用它所指向的成员函数 三、运算符重载的正常使用
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;};// 重载成全局, 无法访问私有成员, 怎么解决?
// 1.提供这些成员get和set
// 2.友元
// 3.重载成成员函数(一般重载成这种)
//// 这里会发现运算符重载成全局的就需要成员变量是公有的那么问题来了封装性如何保证?
// 这里其实可以用我们后面学习的友元解决或者干脆重载成成员函数
bool operator(const Date d1, const Date d2)
{return d1._year d2._year d1._month d2._month d1._day d2._day;
}// d1 - d2
// d1 d2 无意义
// d1 * d2 无意义
// 一个类要重载哪些运算符是看需求, 看重载有没有价值和意义 int main()
{Date d3(2024, 4, 14);Date d4(2024, 4, 15);// 显示调用(可以正常使用)operator(d3, d4);// 直接写,转换调用,编译器会转换成operator(d3, d4)d3 d4;return 0;
} 四、重载成成员函数
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}d3.Func(d4);//bool Func(const Date d)//{// return this-_year d._year// this-_month d._month// this-_day d._day;//}// d3.operator(d4);bool operator(const Date d){cout 类中;return _year d._year _month d._month _day d._day;// 隐藏了this指针/*return this-_year d._year this-_month d._month this-_day d._day;*/}//private:int _year;int _month;int _day;
};// 如果全局和类中都有运算符重载函数编译器会选择调用类里的
bool operator(const Date d1, const Date d2)
{cout 全局;return d1._year d2._year d1._month d2._month d1._day d2._day;
}
int main()
{Date d3(2024, 4, 14);Date d4(2024, 4, 15);// 显式调用d3.operator(d4);// 转换调用 等价于d3.operator(d4);d3 d4;return 0;
}
通过d3.operator(d4)显式调用了类内的operator函数。因为这里是直接通过对象d3来调用的所以肯定是类内的版本被调用。d3 d4这种简洁的写法在C中会被自动转换为对operator的调用。当有多个版本的operator可用时如本例中的类内和全局版本C会根据一定的规则如作用域和参数匹配来选择调用哪一个。在这个例子中由于类内的版本是成员函数且其参数与全局版本相同所以编译器会优先选择类内的版本。 五、赋值运算符重载
1.赋值运算符重载格式
参数类型const T传递引用可以提高传参效率返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值检测是否自己给自己赋值返回*this 要复合连续赋值的含义 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(2024, 4, 14);// 拷贝构造// 一个已经存在的对象拷贝给另一个要创建初始化的对象Date d2(d1);Date d3 d1;Date d4(2024, 5, 1);// 赋值拷贝/赋值重载// 一个已经存在的对象拷贝赋值给另一个已经存在的对象d1 d4;d1 d2 d4;return 0;
} Date operator(const Date d)这个函数重载了赋值运算符允许我们使用来将一个Date对象的值赋给另一个已经存在的Date对象。函数中首先检查自赋值的情况即确保赋值操作的左右两边不是同一个对象然后复制右边的对象的年、月和日到左边的对象并返回左边对象的引用以支持连续赋值操作。*this是对象本身对象在main的作用域里创建因此出main作用域才析构销毁。而出函数作用域不会销毁所以此处才能return *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 Date(const Date d) endl;_year d._year;_month d._month;_day d._day;}void Print(){cout _year - _month - _day endl;}~Date(){cout ~Date() endl;_year -1;_month -1;_day -1;}private:int _year;int _month;int _day;
}; Date(const Date d)这是一个拷贝构造函数它接受一个Date对象的引用并创建一个新的Date对象其内容与传入的对象相同。
有没有办法不生成拷贝
使用引用返回
Date func()
{Date d(2024, 4, 14);return d;
}int main()
{const Date ref func();ref.Print();return 0;
} 在main函数中首先通过调用func函数获取了一个对Date对象的常量引用ref。由于func返回的是一个临时对象这个对象在表达式结束后就会被销毁。但是由于ref是对这个临时对象的引用所以这个临时对象的生命周期会被延长直到ref的生命周期结束。这是C11引入的引用折叠和生命周期延长规则的结果。 Date func()
{Date d(2024, 4, 14);//cout d endl;return d;
}int fx()
{int a 1;int b 2;int c 3;return a b c;
}int main()
{//Date ref func();const Date ref func();cout ref endl;fx();return 0;
}在main函数中通过const Date ref func();获取了func函数返回的引用并将其存储在常量引用ref中。由于func返回的是对局部变量的引用这里的ref实际上引用了一个已经不存在的对象因此这是不安全的 Date func()
{static Date d(2024, 4, 14);return d;
}
// 出了作用域返回对象还在没有析构那就可以用引用返回减少拷贝
// a、返回对象生命周期到了会析构传值返回
// b、返回对象生命周期没到不会析构传引用返回int main()
{const Date ref func();//ref.Print();return 0;
} func函数返回一个对静态局部变量d的引用该变量在函数第一次被调用时被初始化并在程序的整个生命周期内持续存在。由于d是静态的它不会在func函数返回后被销毁因此可以安全地返回它的引用。 在main函数中调用了func函数并将返回的引用赋值给const Date ref。由于返回的是引用因此没有发生任何拷贝操作这是效率更高的做法。 2. 赋值运算符只能重载成类的成员函数不能重载成全局函数
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}int _year;int _month;int _day;
};
// 赋值运算符重载成全局函数注意重载成全局函数时没有this指针了需要给两个参数
Date operator(Date left, const Date right)
{if (left ! right){left._year right._year;left._month right._month;left._day right._day;}return left;
}
// 编译失败
// error C2801: “operator ”必须是非静态成员原因赋值运算符如果不显式实现编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值运算符重载只能是类的成员函数。
3. 用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。
注意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
class Time
{
public:Time(){_hour 1;_minute 1;_second 1;}Time operator(const Time t){if (this ! t){_hour t._hour;_minute t._minute;_second t._second;}return *this;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year 1970;int _month 1;int _day 1;// 自定义类型Time _t;
};
int main()
{Date d1;Date d2;d1 d2;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;s2 s1;return 0;
}注意如果类中未涉及到资源管理赋值运算符是否实现都可以一旦涉及到资源管理则必须要实现。
六、前置和后置重载
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}// 前置返回1之后的结果// 注意this指向的对象函数结束后不会销毁故以引用方式返回提高效率Date operator(){_day 1;return *this;}// 后置// 前置和后置都是一元运算符为了让前置与后置形成能正确重载// C规定后置重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器自动传递// 注意后置是先使用后1因此需要返回1之前的旧值故需在实现时需要先将this保存一份然后给this 1// 而temp是临时对象因此只能以值的方式返回不能返回引用Date operator(int){Date temp(*this);_day 1;return temp;}
private:int _year;int _month;int _day;
};void test02()
{Date d1(2024, 4, 14);Date d2 d1;d1.Print();d2.Print();Date d3 d1;d1.Print();d3.Print();/*d1.operator(1);d1.operator(100);d1.operator(0);d1.Print();*/
}int main()
{test02();return 0;
} 今天就先到这了 看到这里了还不给博主扣个 ⛳️ 点赞☀️收藏 ⭐️ 关注
你们的点赞就是博主更新最大的动力 有问题可以评论或者私信呢秒回哦。