C++基础(三)——面向对象

01 类和对象、this指针

C++ OOP面向对象 OOP编程,this指针

C: 各种各样的函数的定义 struct

C++:类 => 实体的抽象类型

实体(属性、行为) -> ADT(abstract data type)

| |

对象 <-(实例化) 类(属性->成员变量 行为->成员方法)

OOP语言的四大特征是什么?

抽象 封装/隐藏 继承 多态

类 -》 商品实体

访问限定符:public公有的 private私有的 protected保护的

#include <iostream>
#include <cstring>

using namespace std;


const int NAME_LEN = 20;
class CGoods
{
public:
   void init(const char *name, double price, int amount);
   void show();

   void setName(char *name) { strcpy(_name, name); }
   void setPrice(double price) { _price = price; }
   void setAmount(int amount) { _amount = amount; }

   const char* getName() { return _name; }
   double getPrice() { return _price; }
   int getAmount() { return _amount; }

private:
   char _name[NAME_LEN];
   double _price;
   int _amount;
};

void CGoods::init(const char *name, double price, int amount) 
{
    strcpy(this->_name, name);
    this -> _price = price;
    this -> _amount = amount;
}

void CGoods::show() 
{
    cout << "name:" << this->_name << endl;
    cout << "price:" << this->_price << endl;
    cout << "amount:" << this->_amount << endl;
}

int main() 
{
    CGoods good1;
    good1.init("bread",20.5,10);
    good1.show();

    good1.setPrice(30.5);
    good1.setAmount(20);
    good1.show();

    CGoods good2;
    good2.init("banana",50.6,4000);
    good2.show();

    system("pause");
    return 0;
}
//使用strcpy函数需要调用头文件<cstring>

运行结果:

image-20220504153748385

02 构造函数和析构函数

构造函数和析构函数

函数的名字和类名一样

没有返回值

OOP实现一个顺序栈

class SeqStack
{
public:
	// 构造函数 SeqStack s1;  SeqStack s2(20);
	SeqStack(int size = 10) // 是可以带参数的,因此可以提供多个构造函数,叫做构造函数的重载
	{
		cout << this << " SeqStack()" << endl;
		_pstack = new int[size];
		_top = -1;
		_size = size;
	}
	// 析构函数
	~SeqStack() // 是不带参数的,所有析构函数只能有一个
	{
		cout << this << " ~SeqStack()" << endl;
		delete[]_pstack;
		_pstack = nullptr;
	}
	void push(int val)
	{
		if (full())
			resize();
		_pstack[++_top] = val;
	}
	void pop()
	{
		if (empty())
			return;
		--_top;
	}
	int top()
	{
		return _pstack[_top];
	}
	bool empty() { return _top == -1; }
	bool full() { return _top == _size - 1; }
private:
	int *_pstack; // 动态开辟数组,存储顺序栈的元素
	int _top; // 指向栈顶元素的位置
	int _size; // 数组扩容的总大小

	void resize()
	{
		int *ptmp = new int[_size * 2];
		for (int i = 0; i < _size; ++i)
		{
			ptmp[i] = _pstack[i];
		} // memcpy(ptmp, _pstack, sizeof(int)*_size); realloc
		delete[]_pstack;
		_pstack = ptmp;
		_size *= 2;
	}
};
SeqStack gs;
int main()
{
	/*
	.data 
	heap
	stack
	*/
	SeqStack *ps = new SeqStack(60); // malloc内存开辟+SeqStack(60)对象构造
	ps->push(70);
	ps->push(80);
	ps->pop();
	cout << ps->top() << endl;
	delete ps; //先调用ps->~SeqStack()+然后free(ps)   delete和free的区别

	// 1.开辟内存  2.调用构造函数
	SeqStack s;
	//s.init(5);  // 对象成员变量的初始化操作

	for (int i = 0; i < 15; ++i)
	{
		s.push(rand() % 100);
	}

	while (!s.empty())
	{
		cout << s.top() << " ";
		s.pop();
	}

	//s.release(); // 释放对象成员变量占用的外部堆内存(外部资源)

	SeqStack s1(50);

	//s1.~SeqStack(); // 析构函数调用以后,我们说对象不存在了

	s1.push(30); // 堆内存的非法访问了!!!

	return 0; // 
}
/*
this指针 =》 类-》很多对象  共享一套成员方法
成员方法,方法的参数都会添加一个this指针

构造函数:
	定义对象时,自动调用的;可以重载的;构造完成,对象产生了
析构函数:
	不带参数,不能重载,只有一个析构函数;析构完成,对象就不存在了
*/

03 深拷贝和浅拷贝

class SeqStack
{
public:
	// 构造函数 
	SeqStack(int size = 10)
	{
		cout << this << " SeqStack()" << endl;
		_pstack = new int[size];
		_top = -1;
		_size = size;
	}
	// 自定以拷贝构造函数 《= 对象的浅拷贝现在有问题了
	SeqStack(const SeqStack &src)
	{
		cout << "SeqStack(const SeqStack &src)" << endl;
		_pstack = new int[src._size];
		for (int i = 0; i <= src._top; ++i)
		{
			_pstack[i] = src._pstack[i];
		}
		_top = src._top;
		_size = src._size;
	}
	// 析构函数
	~SeqStack() 
	{
		cout << this << " ~SeqStack()" << endl;
		delete[]_pstack;
		_pstack = nullptr;
	}
	// 赋值重载函数 s1 = s1;
	void operator=(const SeqStack &src)
	{
		cout << "operator=" << endl;
		// 防止自赋值
		if (this == &src)
			return;

		// 需要先释放当前对象占用的外部资源
		delete[]_pstack;

		_pstack = new int[src._size];
		for (int i = 0; i <= src._top; ++i)
		{
			_pstack[i] = src._pstack[i];
		}
		_top = src._top;
		_size = src._size;
	}
	void push(int val)
	{
		if (full())
			resize();
		_pstack[++_top] = val;
	}
	void pop()
	{
		if (empty())
			return;
		--_top;
	}
	int top()
	{
		return _pstack[_top];
	}
	bool empty() { return _top == -1; }
	bool full() { return _top == _size - 1; }
private:
	int *_pstack; // 动态开辟数组,存储顺序栈的元素
	int _top; // 指向栈顶元素的位置
	int _size; // 数组扩容的总大小

	void resize()
	{
		int *ptmp = new int[_size * 2];
		for (int i = 0; i < _size; ++i)
		{
			ptmp[i] = _pstack[i];
		} // memcpy(ptmp, _pstack, sizeof(int)*_size); realloc
		delete[]_pstack;
		_pstack = ptmp;
		_size *= 2;
	}
};
int main()
{
	SeqStack s; // 没有提供任何构造函数的时候,会为你生成默认构造和默认析构,是空函数
	SeqStack s1(10);
	SeqStack s2 = s1; // #1  默认拷贝构造函数-》做直接内存数据拷贝
	//SeqStack s3(s1); // #2

	// s2.operator=(s1) 
	// void operator=(const SeqStack &src)
	s1 = s1; // 默认的赋值函数 =》 做直接的内存拷贝 

	return 0;
}

循环队列

class Queue
{
public:
	Queue(int size = 5)
	{
		_pQue = new int[size];
		_front = _rear = 0;
		_size = size;
	}
	//Queue(const Queue&) = delete;
	//Queue& operator=(const Queue&) = delete;
	Queue(const Queue &src)
	{
		_size = src._size;
		_front = src._front;
		_rear = src._rear;
		_pQue = new int[_size];
		for (int i = _front; 
			i != _rear; 
			i = (i + 1) % _size)
		{
			_pQue[i] = src._pQue[i];
		}
	}
	Queue& operator=(const Queue &src)
	{
		if (this == &src)
			return *this;

		delete[]_pQue;

		_size = src._size;
		_front = src._front;
		_rear = src._rear;
		_pQue = new int[_size];
		for (int i = _front;
			i != _rear;
			i = (i + 1) % _size)
		{
			_pQue[i] = src._pQue[i];
		}
		return *this;
	}
	~Queue()
	{
		delete[]_pQue;
		_pQue = nullptr;
	}
	void push(int val) // 入队操作
	{
		if (full())
			resize();
		_pQue[_rear] = val;
		_rear = (_rear + 1) % _size;
	}
	void pop() // 出队操作
	{
		if (empty())
			return;
		_front = (_front + 1) % _size;
	}
	int front() // 获取队头元素
	{
		return _pQue[_front];
	}
	bool full() { return (_rear + 1) % _size == _front; }
	bool empty() { return _front == _rear; }
private: 
	int *_pQue; // 申请队列的数组空间
	int _front; // 指示队头的位置
	int _rear;  // 指示队尾的位置
	int _size;  // 队列扩容的总大小

	void resize()
	{
		int *ptmp = new int[2 * _size];
		int index = 0;
		for (int i = _front;
			i != _rear;
			i = (i + 1) % _size)
		{
			ptmp[index++] = _pQue[i];
		}
		delete[]_pQue;
		_pQue = ptmp;
		_front = 0;
		_rear = index;
		_size *= 2;
	}
};
int main()
{
	Queue queue;
	for (int i = 0; i < 20; ++i)
	{
		queue.push(rand() % 100);
	}

	while (!queue.empty())
	{
		cout << queue.front() << " ";
		queue.pop();
	}
	cout << endl;

	Queue queue1 = queue;
	queue1 = queue;

	return 0;
}

浅拷贝:自定义拷贝构造函数和赋值重载函数

String类型

循环队列 Queue

class String
{
public:
	String(const char *str = nullptr) // 普通构造函数
	{
		if (str != nullptr)
		{
			m_data = new char[strlen(str) + 1];
			strcpy(this->m_data, str);
		}
		else
		{
			m_data = new char[1]; // new char;
			*m_data = '\0'; // 0
		}
	}
	String(const String &other)  // 拷贝构造函数
	{
		m_data = new char[strlen(other.m_data) + 1];
		strcpy(m_data, other.m_data);
	}
	~String(void)  // 析构函数
	{
		delete[]m_data;
		m_data = nullptr;
	}
	// String& 是为了支持连续的operator=赋值操作
	String& operator=(const String &other) // 赋值重载函数
	{
		if (this == &other)
		{
			return *this;  // str1
		}

		delete[]m_data;

		m_data = new char[strlen(other.m_data) + 1];
		strcpy(m_data, other.m_data);
		return *this; // str1
	}
private:
	char *m_data; // 用于保存字符串
};
int main()
{
	// 调用带const char*参数的构造函数
	String str1;
	String str2("hello");
	String str3 = "world";

	// 调用拷贝构造函数
	String str4 = str3;
	String str5(str3);

	// 调用赋值重载函数
	/*
	str1 = str2
	str1.operator=(str2) => str1
	str3 = str1
	*/
	str3 = str1 = str2;

	return 0;
}

04 类和对象应用实例

例1

class Test
{
public:
	Test(int data = 10) :mb(data), ma(mb) {}
	void show() { cout << "ma:" << ma << " mb:" << mb << endl; }
private:
	// 成员变量的初始化和它们定义的顺序有关,和构造函数初始化列表中出现的先后顺序无关!
	int ma;
	int mb;
};
int main()
{
	Test t; // 0xCCCCCCCC  -858993460  
	t.show();
	return 0;
}

例2

/*
日期类
*/
class CDate
{
public:
	CDate(int y, int m, int d) // 自定义了一个构造函数,编译器就不会再产生默认构造了
	{
		_year = y;
		_month = m;
		_day = d;
	}
	void show()
	{
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

05 构造函数的初始化列表

class CGoods
{
public:
	// “CDate”: 没有合适的默认构造函数可用
	CGoods(const char *n, int a, double p, int y, int m, int d)
		:_date(y, m, d)
		,_amount(a) // int _amount = a;
		,_price(p) // #1 构造函数的初始化列表
	{
		// #2 当前类类型构造函数体
		strcpy(_name, n);
	}
	void show()
	{
		cout << "name:" << _name << endl;
		cout << "amount:" << _amount << endl;
		cout << "price:" << _price << endl;
		_date.show();
	}
private:
	char _name[20];
	int _amount;
	double _price;
	CDate _date;  // 成员对象  1.分配内存  2.调用构造函数
};
int main()
{
	CGoods good("商品", 100, 35.0, 2019, 5, 12);
	good.show();

	return 0;
}

06 类的各种成员方法

类的各种成员 - 成员方法/变量

普通的成员方法 => 编译器会添加一个this形参变量

1.属于类的作用域

2.调用该方法时,需要依赖一个对象(常对象是无法调用的 实参:const CGoods* CGoods *this)

3.可以任意访问对象的私有成员 protected继承 public private

static静态成员方法 => 不会生成this形参

1.属于类的作用域

2.用类名作用域来调用方法

3.可以任意访问对象的私有成员,仅限于不依赖对象的成员(只能调用其它的static静态成员)

const常成员方法 => const CGoods *this

1.属于类的作用域

2.调用依赖一个对象,普通对象或者常对象都可以

3.可以任意访问对象的私有成员,但是只能读,而不能写

class CGoods
{
public:
	// “CDate”: 没有合适的默认构造函数可用
	CGoods(const char *n, int a, double p, int y, int m, int d)
		:_date(y, m, d)
		, _amount(a) // int _amount = a;
		, _price(p) // #1 构造函数的初始化列表
	{
		// #2 当前类类型构造函数体
		strcpy(_name, n);
		_count++; // 记录所有产生的新对象的数量
	}
	// 普通成员方法
	void show() // 打印商品的私有的信息 CGoods *this
	{
		cout << "name:" << _name << endl;
		cout << "amount:" << _amount << endl;
		cout << "price:" << _price << endl;
		_date.show();
	}
	// 常成员方法  只要是只读操作的成员方法,一律实现成const常成员方法
	void show()const // const CGoods *this
	{
		cout << "name:" << _name << endl;
		cout << "amount:" << _amount << endl;
		cout << "price:" << this->_price << endl;
		_date.show();
	}
	// 静态成员方法 没有this指针的
	static void showCGoodsCount() // 打印的是所有商品共享的信息
	{
		cout << "所有商品的种类数量是:" << _count << endl;
	}
private:
	char _name[20];
	int _amount;
	double _price;
	CDate _date;  // 成员对象  1.分配内存  2.调用构造函数
	static int _count; // 不属于对象,而是属于类级别的 声明 用来记录商品对象的总数量
};
// static成员变量一定要在类外进行定义并且初始化
int CGoods::_count = 0;
int main()
{
	CGoods good1("商品1", 100, 35.0, 2019, 5, 12);
	good1.show();

	CGoods good2("商品2", 100, 35.0, 2019, 5, 12);
	good2.show();

	CGoods good3("商品3", 100, 35.0, 2019, 5, 12);
	good3.show();

	CGoods good4("商品4", 100, 35.0, 2019, 5, 12);
	good4.show();

	// 统计所有商品的总数量
	CGoods::showCGoodsCount();

	const CGoods good5("非卖品商品5", 100, 35.0, 2019, 5, 12);
	good5.show(); // CGoods::show(&good5)  const CGoods*  -> const CGoods *this

	return 0;
}

07 指向类成员的指针

#include <iostream>
using namespace std;

/*
指向类成员(成员变量和成员方法)的指针
*/
class Test
{
public:
	void func() { cout << "call Test::func" << endl; }
	static void static_func() { cout << "Test::static_func" << endl; }

	int ma;
	static int mb;
};
int Test::mb;
int main()
{
	Test t1;
	Test *t2 = new Test();

	// 指向成员方法的指针
	// 无法从“void (__thiscall Test::* )(void)”转换为“void (__cdecl *)(void)”
	void (Test::*pfunc)() = &Test::func;
	(t1.*pfunc)();
	(t2->*pfunc)();

	// 如何定义函数指针指向类的static成员方法呢?

#if 0
	// int a=10; int *p=&a; *p=30;
	//无法从“int Test::* ”转换为“int *”
	int Test::*p = &Test::ma;
	t1.*p = 20;
	cout << t1.*p << endl;

	t2->*p = 30;
	cout << t2->*p << endl;

	int *p1 = &Test::mb;
	*p1 = 40;
	cout << *p1 << endl;
#endif

	delete t2;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-特立独行的猪-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值