内存对齐规则

1.第一个成员函数在与结构体偏移量为0的地址处
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处
3.对齐数一般为编译器默认的一个对齐数与该成员大小的比较小的值
4.结构体的大小为:最大对齐数(所有变量最大者与默认对齐数参数取最小)的整数倍
5.如果嵌套了结构体,算两步,嵌套的结构体对齐到自己的最大对齐整数倍中,结构体的整体大小就是所有最大对齐数的整数倍。
6.如果结构体中未声明变量,那么对象的大小为1字节,是为了占位标识对象的存在。

this指针

对象中为了区分不同的对象调用相同的类成员函数,在编译器编译后,类的成员函数默认都会在形参的第一个位置,参加一个当前类的指针,叫做this指针。

class Date{
public:
	void Print(int ,year,int month,int day){
	//void Print(Date* const this,int year,int month,int day);
	this->_year=year;
	_month=month;
	.....;
	}
	//这里其实是隐藏了this指针,在c++中规定
	//,this指针不能再形参和实参的位置出现,但是可以在函数体中出现。
private:
	int _year;
	int _month;
	int _day;//只是声明没有开空间
}

构造函数

构造函数是特殊的成员函数,是对象实例化是初始化对象。构造函数的本质是代替了Init()功能,构造函数自动调用。
特点:
1.函数名与类名相同
2.无返回值(不用写void)
3.对象实例化时系统会自动调用对应的构造函数
4.构造函数可以重载
5.如果没有写,编译器会自动生成,一个无参构造,对内置成员不做处理,自定义类型成员会调用它的构造函数
6.无参构造函数,全缺省函数构造都叫默认函数构造,不传实参就可以调用的函数,叫默认构造

#include <iostream>
using namespace std;
class MyClass {
public:
	//1.无参构造
	MyClass() {
		cout << "无参构造函数调用" << endl;
	}
	//2.有参构造
	MyClass(int a) {
		cout << "有参构造函数调用,参数值为:" << a << endl;
	}
	//3.全缺省构造
	MyClass(int a = 0) {
		_a = a;
		cout << "全缺省构造函数调用,参数值为:" << a << endl;
	}

	
private:
	int _a;

};
int main() {

	//调用无参构造
	MyClass obj1;
	//调用有参构造
	MyClass obj2(10);
	//这里如果不注释掉会报错,原因是调用有参构造和全缺省构造时会产生二义性
	return 0;
}

初始化列表

无论是否显示写初始化列表,每个构造函数都有初始化列表
且初始化是按照声明顺序来给值。

隐式转换

在构造前加explicit就不再支持隐式类型转换

#include <iostream>
using namespace std;
class A {
public:
	A(int data = 0)
		:_data(data)//初始化列表
		, _ref(_data)
	{
	};
	A(int data, int data1)
		:_data(data), _data1(data1)//初始化列表
		, _ref(_data)
	{
	};
	void PrintData()const {
		cout << _data << _data1 << endl;
	}
private:
	int _data;
	int _data1;
	int& _ref;//引用成员必须初始化
	const int _a = 0; //const成员必须初始化
};
int main() {
	A a = 2;
	//阴式类型转换,2先构造一个A的临时对象,然后用这个临时对象拷贝构造a
	//编译器遇到连续的构造+拷贝构造——》优化为直接构造
	//explict关键字可以阻止隐式类型转换
	a.PrintData();
	const A& b = 3;
	//b.PrintData();//eroor
	const A& c = { 4,5 };//,const 引用可以绑定到临时对象(延长其生命周期)。
	c.PrintData();
	// const 修饰的对象(或通过 const 引用访问的对象),只能调用 const 成员函数。
	// 这是因为非 const 成员函数可能会修改对象的成员变量,而 const 对象的状态不允许被修改。
	return 0;
}

static成员

用static修饰的成员变量,一定要在类外进行初始化,静态成员为所有类对象所共享,不属于某个具体的对象,不存在对象之中,放在静态区。
静态成员没有this指针
静态成员可以访问其他静态成员,但不能访问非静态的,非静态可以任意访问。
静态成员不能再声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不走构造函数初始化列表

#include <iostream>
using namespace std;	
class A {
public:
	static int _a;//静态成员变量声明
	void PrintA() {
		cout << _a << endl;
	}
};
int A::_a = 10; //静态成员变量定义和初始化
int main() {
	A a1;
	A a2;
	a1.PrintA();
	a2.PrintA();
	A::_a = 20; //通过类名修改静态成员变量
	a1.PrintA();
	a2.PrintA();
	return 0;
}

析构函数

c++规定对象在销毁是会自动调用析构函数,完成对象中资源的清理释放。
特点:
1.函数名前加~
2.无参数返回值
3.一个类只能有一个析构函数,若未定义,系统会自动默认生成析构函数
4.对象生命周期结束时系统会自动调用析构函数
5.跟构造函数一样,我们不写,编译器会自动生成析构函数对内置成员不做处理,自定义类型成员会调用它的析构函数。
6.自定义类的成员无论什么情况都会调用析构函数。

//析构函数
~MyClass() {
	cout << "析构函数调用" << endl;
}//自己调用自己

程序结束,自己调用

拷贝构造

拷贝构造是一个特殊的构造函数
特点:

  1. 拷贝构造就是构造函数的一个重载
  2. 第一个参数必须是类型对象的引用,使用传值方式编译直接回报错,传值会产生一个临时对象,对象再去调用对象的拷贝构造,就会无限递归。且后面的参数必须有缺省值
  3. 未定义时,编译器自动生成,自动生成的拷贝构造,对内置类型会完成值拷贝(浅拷贝),对自定义类型对调用它的拷贝构造函数。
  4. 深拷贝需要自己去定义
MyClass(const MyClass& obj) {
	_a = obj._a;
	cout << "拷贝构造函数调用,参数值为:" << _a << endl;
}

运算符重载

运算符重载是具有特殊名字的函数,它的名字是由operator和后面要定义的运算符共同构成。和其它函数一样,它也具有其返回类型以及参数列表以及函数体。

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;

};

// 全缺省的构造函数
Date::Date(int year, int month, int day)
{
	_year = year;
	_month = month;
	_day = day;
}
// 拷贝构造函数
Date::Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
// 赋值运算符重载
Date& Date::operator=(const Date& d)
{
	if (this != &d) // 防止自赋值
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	return *this;
}


// 获取某年某月的天数
int Date::GetMonthDay(int year, int month)
{
	static int days[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
	// 闰年2月29天
	if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
	{
		days[1] = 29;
	}
	return days[month - 1];
}
// 析构函数
Date::~Date()
{
}
// 日期+=天数
Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_month = 1;
			_year++;
		}
	}
	return *this;
}

// 日期+天数
Date Date::operator+(int day)
{
	Date temp = *this;
	temp += day;
	return temp;
}
// 日期-天数
Date Date::operator-(int day)
{
	Date temp = *this;
	temp -= day;
	return temp;
}
// 日期-=天数
Date& Date::operator-=(int day)
{
	_day -= day;
	while (_day <= 0)
	{
		_month--;
		if (_month <= 0)
		{
			_month = 12;
			_year--;
		}
		_day += GetMonthDay(_year, _month);
	}
	return *this;
}
// 前置++
Date& Date::operator++()
{
	*this += 1;
	return *this;
}
// 后置++
Date Date::operator++(int)
{
	Date temp = *this;
	*this += 1;
	return temp;
}
// 后置--
Date Date::operator--(int)
{
	Date temp = *this;
	*this -= 1;
	return temp;
}
// 前置--
Date& Date::operator--()
{
	*this -= 1;
	return *this;
}
// >运算符重载
bool Date::operator>(const Date& d)
{
	if (_year != d._year)
		return _year > d._year;
	if (_month != d._month)
		return _month > d._month;
	return _day > d._day;
}
// ==运算符重载
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);
}
// !=运算符重载
bool Date::operator!=(const Date& d)
{
	return !(*this == d);
}
// 日期-日期 返回天数
int Date::operator-(const Date& d)
{
	Date temp1 = *this;
	Date temp2 = d;
	int days1 = 0;
	int days2 = 0;
	// 计算当前日期到1900年1月1日的天数
	for (int year = 1900; year < temp1._year; year++)
	{
		days1 += 365;
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			days1++;
	}
	for (int month = 1; month < temp1._month; month++)
	{
		days1 += GetMonthDay(temp1._year, month);
	}
	days1 += temp1._day;
	// 计算另一个日期到1900年1月1日的天数
	for (int year = 1900; year < temp2._year; year++)
	{
		days2 += 365;
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			days2++;
	}
	for (int month = 1; month < temp2._month; month++)
	{
		days2 += GetMonthDay(temp2._year, month);
	}
	days2 += temp2._day;
	return days1 - days2;
}

int main() {
	Date d1(2024, 3, 14);
	Date d2 = d1; // 调用拷贝构造函数
	Date d3;
	d3 = d1; // 调用赋值运算符重载
	Date d4 = d1 + 10; // 日期加天数
	Date d5 = d1 - 5; // 日期减天数
	d1 += 20; // 日期加天数
	d2 -= 15; // 日期减天数
	++d1; // 前置++
	d2++; // 后置++
	--d3; // 前置--
	d4--; // 后置--
	bool b1 = d1 > d2; // 大于比较
	bool b2 = d3 == d4; // 等于比较
	int daysDiff = d1 - d2; // 日期差值
	return 0;
}


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐