c++类和对象(this指针,重载operator,习题总结)

this指针

在c++类中默认含有this指针,并且在主函数调用实参时不能被写出,c++是不允许的

cpp 复制代码
class date//定义类=struct
{
public://公开
	void Init(int year, int month, int day)//日期类的初始化
	{

		_year = year;
		_month = month;
		_day = day;
	}

	void print(int year,int month,int day)
	{

		cout << year << "/" << month << "/" << day << endl;

	}
private://私人
	int _year;//成员变量
	int _month;
	int _day;

};//分号不能省略

int main()
{
	date a;
	date b;
	a.Init(2026,7,12);
	a.print(2026,7,12);
	b.Init(2026,3,12);
	b.print(2026,3,12);
	//共用一个函数,但是打印的结果不同,这是为什么?
	return 0;

当然我们也可以这样写:

cpp 复制代码
#include<iostream>
using namespace std;
class date//定义类=struct
{
public://公开
	void Init(int year, int month, int day)//日期类的初始化
	{

		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

	//void print(date*const this)//隐式,不能写
	void print()
	{

		cout << this->_year << "/" << this->_month << "/" << this->_day << endl;

	}
private://私人
	int _year;//成员变量
	int _month;
	int _day;

};//分号不能省略

int main()
{
	date a;
	date b;
	a.Init(2026,7,12);
	a.print();
	b.Init(2026,3,12);
	b.print();
	//共用一个函数,但是打印的结果不同,这是为什么?
	return 0;


}

小练习:this指针是放在哪里的: 一般放在栈

private:中的成员只是声明,没有开空间,必须要等到对象实例化才行

重载operator

1. 运算符重载的基本概念

运算符重载的本质是函数重载。当我们使用一个运算符(如+, -, ==)时,编译器会将其转换为对特定运算符函数的调用。对于自定义类型,我们可以自己定义这个函数。

重载规则与限制:

  • 可重载的运算符 :大部分C++运算符都可以重载,例如算术运算符(+, -, *, /)、关系运算符(==, !=, <, >)、逻辑运算符(&&, ||)、赋值运算符(=)、下标运算符([])、函数调用运算符(())等。
  • 不可重载的运算符 :成员访问运算符(.)、成员指针运算符(.*)、作用域解析运算符(::)、条件运算符(?:)、sizeof运算符以及typeid运算符。
  • 操作数数量:重载后的运算符必须保持其原有的操作数数量(一元或二元)。
  • 至少一个操作数为用户自定义类型:不能为两个内置类型重载一个新的运算符。

2. 运算符重载的语法

运算符重载函数可以是类的成员函数 ,也可以是非成员函数(通常是友元函数)

2.1 作为成员函数重载

当运算符重载为类的成员函数时,它的第一个(对于二元运算符)或唯一一个(对于一元运算符)操作数隐式地是调用该函数的对象本身(即*this)。

语法格式:

cpp 复制代码
返回类型 operator运算符符号 (参数列表) {
    // 函数体
}

示例:重载+运算符实现两个Date对象的日期相加(按天数)

cpp 复制代码
class Date {
public:
    Date(int year = 1970, int month = 1, int day = 1)
        : _year(year), _month(month), _day(day) {}

    // 成员函数重载 + 运算符
    Date operator+(int days) const {
        Date temp(*this); // 创建当前对象的副本
        temp._day += days;
        // 这里应添加处理月份和年份进位的逻辑,为简化示例省略
        // 例如,当temp._day大于当月天数时,月份+1,天数重置
        return temp; // 返回新对象,不改变原对象
    }

    void Print() const {
        cout << _year << "/" << _month << "/" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main() {
    Date d1(2026, 7, 23);
    Date d2 = d1 + 5; // 等价于 d1.operator+(5)
    d2.Print(); // 输出:2026/7/28 (假设)
    return 0;
}
2.2 作为非成员函数(友元)重载

有些运算符,如输入输出运算符(<<, >>),其左侧操作数是流对象(ostream/istream),而不是自定义类的对象,因此必须定义为非成员函数。为了能访问类的私有成员,通常将其声明为类的friend(友元)。

示例:重载<<运算符方便输出

cpp 复制代码
#include <iostream>
using namespace std;

class Date {
    // 声明友元函数
    friend ostream& operator<<(ostream& out, const Date& d);
public:
    Date(int year = 1970, int month = 1, int day = 1)
        : _year(year), _month(month), _day(day) {}

private:
    int _year;
    int _month;
    int _day;
};

// 定义全局的 operator<< 函数
ostream& operator<<(ostream& out, const Date& d) {
    out << d._year << "/" << d._month << "/" << d._day;
    return out; // 支持链式调用,如 cout << d1 << " " << d2;
}

int main() {
    Date d(2026, 7, 23);
    cout << "Today is: " << d << endl; // 直接使用 << 输出Date对象
    return 0;
}

3. 特殊运算符重载示例

3.1 前置++与后置++

为了区分前置和后置递增,C++规定后置版本接受一个额外的int类型参数(该参数无实际意义,仅用于区分)。

cpp 复制代码
class Counter {
public:
    Counter(int val = 0) : value(val) {}

    // 前置++:返回递增后的对象的引用
    Counter& operator++() {
        ++value;
        return *this;
    }

    // 后置++:参数int仅用于区分,返回递增前的对象副本
    Counter operator++(int) {
        Counter temp = *this;
        ++value; // 或者 ++(*this)
        return temp;
    }

    int getValue() const { return value; }

private:
    int value;
};

int main() {
    Counter c(5);
    Counter a = ++c; // 前置:c先加1,再赋值给a
    cout << "a: " << a.getValue() << ", c: " << c.getValue() << endl; // a:6, c:6

    Counter b = c++; // 后置:c先赋值给b,再加1
    cout << "b: " << b.getValue() << ", c: " << c.getValue() << endl; // b:6, c:7
    return 0;
}
3.2 赋值运算符=

赋值运算符通常需要深拷贝,并处理自赋值情况。它应返回对象的引用以支持链式赋值(a = b = c)。

cpp 复制代码
class MyString {
public:
    MyString(const char* str = nullptr) {
        if (str) {
            data = new char[strlen(str) + 1];
            strcpy(data, str);
        } else {
            data = new char[1];
            *data = '\0';
        }
    }
    // 拷贝构造函数(略)
    // 析构函数(略)

    // 重载赋值运算符
    MyString& operator=(const MyString& other) {
        if (this != &other) { // 1. 检查自赋值
            delete[] data; // 2. 释放原有资源
            data = new char[strlen(other.data) + 1]; // 3. 申请新资源
            strcpy(data, other.data); // 4. 拷贝数据
        }
        return *this; // 5. 返回自身引用
    }

private:
    char* data;
};

4. 习题解析与常见问题

习题总结:

x的值不变,因为xconst修饰,operator++函数不能改变const对象的值。

运算符重载问题:

该图可能展示了关于运算符重载优先级、结合性或定义冲突的典型问题。例如,重载&&||会失去短路求值特性;重载逗号运算符,可能改变求值顺序。在设计重载时,应尽量保持运算符的原始语义,避免造成使用者的困惑。

5. 总结

  • 前置++Counter& operator++(); 返回引用,效率高。
  • 后置++Counter operator++(int); 返回副本,参数int为占位符。
  • ++是单目运算符,所以作为成员函数重载时没有显式参数(后置的int除外)。
相关推荐
霸道流氓气质1 小时前
基于 Spring 事务同步机制的事务后置动作收集器 Starter 实践
java·后端·spring
过期动态1 小时前
【LeetCode 热题 100】找到字符串中所有字母异位词
java·数据结构·算法·leetcode·职场和发展·rabbitmq
皓月斯语2 小时前
程序设计语言的特点
开发语言·数据结构·c++
超人不会飞_Jay2 小时前
Go课程2
开发语言·后端·golang
刘小八2 小时前
Spring AI Tool Calling 生产化:参数校验、权限控制与超时隔离
java·人工智能·spring
奶糖 肥晨2 小时前
一次Spring Boot编译报错排查:三元运算符与包装类型的“隐形陷阱”
java·spring boot·后端
谢栋_2 小时前
设计模式从入门到精通之(七)责任链模式
java·设计模式·责任链模式
Billy121382 小时前
结构化绑定与 if constexpr
开发语言·c++进阶学习
愚公移码2 小时前
蓝凌EKP18产品:核心执行流程
java·流程引擎