自学C++ day02 (OOP)

本文详细介绍了C++中的类和对象,包括类的声明与定义分离、访问权限、对象存储、内存对齐规则、this指针、构造函数、析构函数、拷贝构造函数、运算符重载、const成员函数、静态成员以及友元。此外,还讨论了对象的生命周期和内存管理,如动态内存分配和析构时的资源释放。
摘要由CSDN通过智能技术生成
#include <iostream> 
#include <assert.h>
using std::cout;
using std::endl;

// 类的声明放在ClassName.h 中,
// 类的定义放在ClassName.cpp 中!
// 开源项目一般将类的声明和定义放在一起ClassName.hpp 中!
class Person {
public:
	void showInfo(); // .h 中声明!
private:
	char* _name;
	char* _sex;
	int _age;
};
// .cpp 中定义!
void Person::showInfo() {
	cout << _name << "-" << _sex << "-" << _age << endl;
}

// 类的访问限定:
//		public: 修饰的成员在类外可以直接访问!
//		private和protected: 修饰的成员在类外不能直接访问!
//		class 的默认访问权限是private,struct是public;


// 类的实例化!
// 类只是一个模型一样的东西,限定了类有那些成员,定义出一个类并没有分配实际的内存空间来存储它!
// 一个类可以实例化出多个对象,实例化的对象占实际的物理空间,存储成员变量!

// 对象是如何存储的?
// 类的变量的值可以是不一样的,但是成员函数的代码是相同的!

class A1 {
public:	
	void f1() {};
private:
	int _a;
};

class A2 {
public:
	void f2() {};
};

class A3 {

};

#if 0
// 可以发现,对象存储时,只将类的成员变量每个成员单独一份,代码是共享的!
int main() {
	A1 a1;
	A2 a2;
	A3 a3;
	cout << sizeof(a1) <<" "<< sizeof(a2) <<" "<<  sizeof(a3) << endl;
	return 0;
}
#endif 


// 结构体内存对齐规则:
// 第一个成员在与结构体偏移量为 0 的地址处!
// 其他成员变量要对齐到某个数字(对齐数 = 编译器默认的堆区数与该成员的大小的较小值!)的整数倍的地址处!
// 结构体的总大小为: 最大对齐数的整数倍(min(所有变量类型最大者,编译器指定对齐数))
// 嵌套大小,嵌套的结构体算作一个成员!



// this 指针:
class Date {
public:
	void Display() {
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	void SetDate(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
// C++ 编译器给每个非静态成员函数增加了一个隐藏的this指针,让该指针指向当前对象,在函数体中所有成员变量的操作都是通过该指针去访问的
// 只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成!
#if 0
int main() {
	Date d1, d2;
	d1.SetDate(2022, 7, 6);
	d2.SetDate(2022, 7, 7);
	d1.Display();
	d2.Display();
	return 0;
}
#endif 

// this 指针的特性:
// 1. this 指针的类型: 类类型* const 
// 2. 只能在成员函数的内部使用!
// 3. this 指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参. 所以对象中不存储this指针!
// 4. this 指针是成员函数第一个隐含的指针参数,一般情况下由编译器通过ecx寄存器自动传递,不需要用户传递!

class A {
public:
	void PrintA() {
		cout << _a << endl;
	}
	void Show() {
		cout << "Show()" << endl;
	}
private:
	int _a;
};

#if 0
//. this 指针的类型: 类类型* const 
int main() {
	Date* p = NULL;
	//p->PrintA();
	//p->Show();
	return 0;

}
#endif 




//默认成员函数:
// 初始化和清理: 构造函数,析构函数!
// 拷贝复制: 使用同类对象初始化创建新对象! 赋值重载主要是把一个对象赋值给另一个对象!
// 取地址重载: 主要是普通对象和 const 对象取地址!


// 1. 构造函数:
// 构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员都有一个合适的初始值
// 并且在对象的生命周期只调用一次!
// 如果一个类没有写构造函数,编译器会自动生成一个无参构造函数!
// 一旦用户显示定义了构造函数,则不会再生成默认的无参构造!
class Time {
public:
	Time() {
		cout << "Time()" << endl;
		_hour = 0;
		_minute = 0;
		_second = 0;
	}
private:
	int _hour;
	int _minute;
	int _second;
};

class Datr{
private:
	// 基本类型,默认赋值!
	int _year;
	int _month;
	int _day; 

	// 自定义类型,调用其无参构造赋值!
	Time _t;
};
#if 0
int mian() {
	Datr d;
	return 0;
}
#endif 


// 2. 析构函数
// 与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是编译器完成的!
// 而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作!
// 特征:
// (1) 析构函数名是在类名前加上~ 
// (2) 无参数无返回值!
// (3) 一个类有且之后一个析构函数。若未显示定义,系统会默认生成析构函数!
// (4) 对象生命周期结束时,C++编译器系统会自动调用析构函数!

typedef int DataType;
class SeqList {
public:
	SeqList(int capacity = 10) :_capacity(capacity) {
		_pData = (DataType*)malloc(capacity * sizeof(DataType));
		assert(_pData);
		_size = 0;
	}

	~SeqList() {
		cout << "~SeqList()" << endl;
		free(_pData); // 释放堆上的空间!
		_pData = nullptr;
		_capacity = 0;
		_size = 0;
	}
private:
	int * _pData;
	size_t _size;
	size_t _capacity;
};

#if 0
int main() {
	SeqList sq;
	return 0;
}
#endif 


// 3. 拷贝构造函数
// 构造函数只有一个形参,且该形参时本类类型对象的引用(一般是 const的),在用已存在的类类型对象创建新对象时由编译器自动调用!
// 特征:
// 拷贝构造函数时构造函数的一个重载形式!
// 拷贝构造函数的参数只有一个且必须使用引用传参,使用传值方式会引发无穷递归调用!
// 如果没有显示定义拷贝函数系统会自动生成拷贝构造函数,默认的拷贝构造函数对象按内存存储字节完成拷贝!(浅拷贝!)
class Data {
public:
	Data(int year = 2022,int month = 1, int day = 1) :_year(year), _month(month), _day(day) {}
	Data(const Data& data) {
		_year = data._year;
		_month = data._month;
		_day = data._day;
	}
private:
	int _year;
	int _month;
	int _day;
};


// 运算符重载:
// C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,
// 函数名字以及参数列表,其返回值类型与参数列表与普通函数类似!
// 函数名字为: 关键字operator后面接需要重载的运算符符号
// 函数原型: 返回值类型 operator操作符(参数列表) 
// 内置类型的操作符,其含义不能改变;
// . * :: sizeof ?:不能重载!

// 全局operator==

class DateA {
public:
	DateA(int year = 1900, int month = 1, int day = 1) :_year(year), _month(month), _day(day) {}
	bool operator==(const DateA& d) {
		return _day == d._day && _month == d._month &&  _year == d._year;
	}
	DateA& operator=(const DateA& d) {
		_year = d._year;
		_day = d._day;
		_month = d._month;
	}

	int _year;
	int _month;
	int _day;
};


void Test() {
	DateA d1(1,2,3);
	DateA d2(2,4,5);
	cout << (d1 == d2) << endl;
	return;
}

#if 0
int main() {
	Test();
	return 0;
}
#endif 


// 7. const 成员
// const 修饰尘缘函数: const 修饰的成员函数称为const成员函数,实际修饰该成员函数隐含的this指针,表明该成员函数中不能对类的任何成员进行修改!

class AnoutConst {
public:
	void show1() {
		cout << "show()" << endl;
	}
	void call(int val) {
		_val = val;
		show();
	}
	void show()const {
		cout << "show() const" << endl;
		// call(3); const 成员函数不能调用非const成员函数!
	}
private:
	int _val;
};


// 取地址以及const 取地址操作符重载!
class AboutCon {
public:
	AboutCon* operator&() {
		return this;
	}
	const AboutCon* operator&() const {
		return this;
	}
private:
	int _val;
};



// 构造方法的初始化列表:
// 1. 每个成员变量在初始化列表中只能出现一次!
// 2. 类中包含一下成员必须放在初始化列表位置进行初始化!
//		(1) 引用成员变量
//		(2) const 成员变量
//		(3) 自定义类型成员变量(该类没有默认构造函数!)
// 3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量一定会使用初始化列表初始化!
// 4. 成员在类中声明次序就是其在初始化列表中的初始化顺序,与其在列表中的先后次序无关!


// 对于单个参数的构造函数,构造函数有类型装欢的作用!
// 使用 explict 修饰构造函数,将会禁止单构造函数隐式转换!



// static 成员:
// 声明为static的类成员,称为类的静态成员. 
// 静态成员变量一定要在类的外部进行初始化!

class B {
public:
	B() {
		_count++;
	}
	B(const B& b) {
		++_count;
	}
	static int GetCount() {
		return _count;
	}
private:
	static int _count;
};
int B::_count = 0;
// 静态成员为所有类对象所共享,不属于某个具体的实例!
// 静态成员变量必须在类外定义,定义时不添加static关键字!
// 静态成员没有隐藏的this指针,不能访问任何非静态成员!
// 静态成员也有访问级别!



// 友元: 突破封装的一种便利!
// 友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但是需要在类的内部声明,声明时要加上friend关键字!
// 友元函数不能用const修饰!
// 友元类: 关系是单项的,A声明B是friend那么B就能访问A的全部,但是A不能访问B的全部!



// 内部类:
// 如过类B定义在类A的内部,那么类B就叫做内部类,但是B是独立的,不依赖A存在而存在!
// 内部类就是外部类的友元类,但是外部类不是内部类的友元类!
// 内部类可以直接访问外部类中的static、枚举成员、不需要外部类的对象/类名!
// sizeof(外部类) = 外部类 ,和内部类没有任何关系!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值