C++中类与对象

类的定义:

java 复制代码
#include<iostream>
using namespace std;
//类的定义:用class关键字来定义,同时也可以用struct替换class,c++中也可以用struct来定义结构体
// 区别是:class默认类中没有权限修饰的成员为私有,而struct默认类中没有权限修饰的成员为公有
//类中可以定义:1.成员变量,2.成员函数
// 类的定义
class 类名 {
    // class访问权限:默认为私有
public:
    // 公开成员(外部可以直接访问)
    //成员函数声明 / 定义;

private:
    // 私有成员(只有类自己能访问,外部不能用)
    //成员变量;
}; //注意:加分号

小知识:

1.size_t 是 C/C++ 里的一个标准无符号整数类型,专门用来表示大小、长度、下标、计数。

如:sizeof(...) 返回值就是 size_t;std::string::size()、vector::size() 都返回 size_t

2.声明和定义的区别:声明是一种承诺,但是还没做,定义就是把这件事给落实了。

案例:定义一个数据结构栈的类

java 复制代码
//定义一个数据结构栈的类
class Stack {
	//成员函数
public:
	//在写函数时,我们可以在类中定义,也可以在类中声明在类外面定义,
	// 如下:
	void Init(size_t n) {//初始化
		//...
	}
	//void Destory() {//销毁
	//	//...
	//}
	//在类中声明
	void Destory();
	void Push(int x) {//入栈
		//...
	}

	void Pop() {//出栈
		//...
	}

	//成员变量
private:
	int* _a;
	size_t _top;
	size_t _capacity;//size_t 是 C/C++ 里的一个标准无符号整数类型
};

//在类外定义,销毁栈
void Stack::Destory() {
	//...
}
class A {

};
int main() {
	//类实例化对象
	Stack s1;
	//计算类的大小
	cout << sizeof(s1) << endl;//12,并没有计算类中函数的大小,为什么呢?
	//答:成员函数存在公共代码区(代码段),所有对象共用一份,不占对象的内存。原因:若一个类实
例化出N个对象,每个对象的成员变量都存不同的值,但调用的函数是同一个,如果每个对象都放成员函数,
而这些成员函数是一样的,会造成空间上的浪费。所以就是实例化对象的大小,就是计算类中成员变量大小
之和,并且要考虑内存对齐规则
	A a1;
	cout << sizeof(a1) << endl;//1,没有成员变量类的大小是1,为什么?
	//答:一个字节不是为了存储数据,而是为了占位,记录对象的地址,保证每个对象有独立地址
	return 0;
}

构造函数

构造函数是用来初始化对象的,在对象创建时,调用这个函数完成对象的初始化操作。

特征:
  1. 函数名与类名相同。

  2. 无返回值。

  3. 对象实例化时编译器自动调用对应的构造函数。

  4. 构造函数可以重载。

  5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦 用户显式定义编译器将不再生成

6.写构造函数的作用:构造函数会对自定类型对象调用的它的默认构造函数,可以将对象中的成员变量初始化为我们所指定的值

初始化调用函数时
java 复制代码
#include<iostream>
using namespace std;
//定义类
class Date {
public:
	//初始化
	void Init(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() {//没有传参数,是因为编译器在运行时隐含this指针,谁调用这个函数,this就指向谁,且this不能为空this是存在栈上的,它是一个形参,:void Print(Date * this)
		cout << _year << "-" << _month << "-" << _day << endl;
        //编译器处理为:	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main() {
	//实例化类
	Date d1;
	d1.Init(2026, 4, 17);
	d1.Print();//编译器处理为:d1.Print(&d1);
	return 0;
}
使用构造函数初始化:我们自己写的构造函数
java 复制代码
//定义类
//使用构造函数初始化对象
class Date {
public:
	Date() {//无参构造
		_year = 0;
		_month = 1;
		_day = 1;
	}
	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;
};
int main() {
	//实例化类
	Date d1;
	d1.Print();
	Date d2(2026,4,17);
	d2.Print();
	return 0;
}
全缺省写法
java 复制代码
//定义类
//使用构造函数初始化对象
class Date {
public:
	//Date() {//无参构造
	//	_year = 0;
	//	_month = 1;
	//	_day = 1;
	//}
	//全缺省写法//不能与上面的无参构造同时存在,会存在歧义
	Date(int year = 0, 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(2026,4,17);
	d2.Print();
	return 0;
}
使用构造函数初始化:编译器自动生成的构造函数
java 复制代码
//定义类
//使用构造函数初始化对象
class Date {
public:
	//没有定义构造函数,编译器自动生成并调用构造函数
	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main() {
	//实例化类
	Date d1;//会调用默认构造函数:1.自己写的无参构造,2.自己实现的全缺省构造函数,3.编译器自动生成的构造函数
	d1.Print();
	
	return 0;
}

析构函数

析构函数:对象生命周期到了以后,自动调用析构函数,完成对象里面的资源清理工作,不是完成对象的销毁工作

特征:
  1. 析构函数名是在类名前加上字符 ~。

  2. 无参数无返回值类型。

  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载

  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

5.如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏。

java 复制代码
//定义类
//使用析构函数完成资源清理工作
class Date {
public:
	//全缺省写法
	Date(int year = 0, int month = 1, int day = 1) {
		cout << "Date:" << this << endl;
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	//析构函数
	~Date() {
		cout << "~Date:" << this << endl;//this:表示当前对象的地址
	}
private:
	int _year;
	int _month;
	int _day;
};
//栈中:后进先出
int main() {
	//实例化类
	Date d1;
	Date d2(2026,4,17);
	return 0;
}

拷贝构造函数

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

特征:
  1. 拷贝构造函数是构造函数的一个重载函数。

  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

    3.若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

拷贝构造:自己写的
java 复制代码
//拷贝构造
class Date {
public:
	//全缺省写法
	Date(int year = 0, int month = 1, int day = 1) {
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造
	//Date(const Date d) {// 错误写法:编译报错,会引发无穷递归 ,参数Date d = d1,又会调用拷贝构造停不下来。
	Date(const Date& d){//正确写法,写成对d1的引用:Date& d = d1;
		_year = d._year;
		_month = d._month;
		_day = d._day;
		//d._day = _day;//加const可以避免写成这样,导致对原来的值进行修改,const表示使用传入的值,不会做任何修改
	}
	void Print() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	
private:
	int _year;
	int _month;
	int _day;
};
int main() {
	//实例化类
	Date d1(2026,4,17);
	Date d2(d1);//拷贝构造,d2与d1相同,等同于:Date d2 = d1;
	return 0;
}
拷贝构造:编译器默认生成的拷贝构造
java 复制代码
//若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	Time(const Time& t)
	{
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
		cout << "Time::Time(const Time&)" << endl;
	}
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;
	// 用已经存在的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
	// 但Date类并没有显式定义拷贝构造函数,则编译器会给Date类生成一个默认的拷贝构造函数
	Date d2(d1);
	return 0;
}

赋值运算符重载

运算符重载是具有特殊函数名的函数,也有返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。

函数名字为:关键字operator后面接需要重载的运算符符号。

格式:返回值类型 operator操作符(参数列表)

注意:

1.不能通过连接其他符号来创建新的操作符:比如operator@

2.重载操作符必须有一个类类型参数

3.用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义

4.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐

藏的this

5.'.*', ' :: ', 'sizeof', ' ?: ', ' . ' 注意以上5个运算符不能重载。

java 复制代码
//赋值运算符重载
class Date {
public:
	Date(int year = 1970, int month = 1, int day = 1) {
		_year = year;
		_month = month;
		_day = day;
	}
	//==运算符重载
	//编译器会解释成这样:bool operator==(Date* this, const Date& d2)
	bool operator==(const Date& d2){
		return _year == d2._year
			&& _month == d2._month
			&& _day == d2._day;

	}
	//>运算符重载
	bool operator>(const Date& d2) {
		if (_year > d2._year) {
			return true;
		}
		else if (_year == d2._year && _month > d2._month) {
			return true;
		}
		else if (_year == d2._year && _month == d2._month && _day > d2._day) {
			return true;
		}
		return false;
	}
private:
	int _year;
	int _month;
	int _day;
};
//自定义类型是不能用运算符的,用的话就得重载运算符
int main() {
	Date d1(2026, 4, 17);
	Date d2(2026, 4, 17);
	cout << (d1 == d2) << endl;
	cout << (d1 > d2) << endl;
}
相关推荐
良木生香2 小时前
【C++初阶】:泛型编程的代表作---C++初阶模板
c语言·开发语言·数据结构·c++·算法
网域小星球2 小时前
C++ 从 0 入门(一)|C++ 基础语法、命名空间、引用、IO 输入输出
开发语言·c++·引用·命名空间·cin/cout
雾岛听蓝2 小时前
Qt按钮与标签控件详解
开发语言·经验分享·笔记·qt
黑牛儿2 小时前
AI Agent\+PHP实现智能接口限流,避开算力成本陷阱(结合今日AI热点)
开发语言·人工智能·php
XMYX-02 小时前
15 - Go 泛型(Generics):从入门到实战
开发语言·golang
Halo_tjn2 小时前
Java 内部类
java·开发语言·算法
碎碎念的安静2 小时前
WPF 与 Qt 进程间通信(IPC)
开发语言·qt·wpf
旖-旎2 小时前
栈(验证栈序列)(5)
c++·算法·leetcode·力扣·
boonya2 小时前
Spring AI 深度实践教程:从“能用”到“用好”
开发语言·python