C++笔记_面向对象

1. 类、对象、this指针

#include <iostream>
using namespace std;
//#define NAME_LEN 20
const int NAME_LEN = 20;
class CGoods//=>商品的抽象数据类型
{
public://给外部提供公有的方法,来访问私有的属性
	//做商品数据初始化用的
	//类体内实现的方法,自动处理成内联函数
	void init(const char* name, double price, int amount); void show();
	//给成员变量提供一个getXXX或setXXX的方法
	void setName(const 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;
};
inline void CGoods::init(const char* name, double price, int amount)
{
	strcpy(_name, name);
	_price = price;
	_amount = amount;
}
void CGoods::show()
{
	cout << "_name:" << _name << endl;
	cout << "price:" << _price << endl;
	cout << "_amount:" << _amount << endl;
}
int main(void)
{
	//CGoods可以定义无数的对象,每一个对象都有自己的成员变量,但是他们共享一套成员方法
	//对象内存大小的时候 对象的内存大小只和成员变量有关
	//show()=>怎么知道处理哪个对象的信息?
	//init(name,price,amount)怎么知道把信息初始化给哪一个对象的?
	//init(&good,"面包",10.0,200)
	//类的成员方法一经编译,所有的方法参数,都会加一个this指针,接收调用该方法的对象的地址	CGoods good;//类实例化了一个对象
	CGoods good;//类实例化了一个对象
	good.init("面包", 10.0, 200);
	good.show();
	good.setPrice(20.5);
	good.setAmount(100);
	good.show();

	CGoods good2;//类实例化了一个对象
	good2.init("空调", 10000.0, 50);
	good2.show();

	return 0;
}

2. 构造函数与析构函数

#include <iostream>
using namespace std;
//OOP实现一个顺序栈
//构造函数和析构函数
class SeqStack
{
public:
	//构造函数
	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,realloc
		}
		delete[]_pstack;//删除原来的空间
		_pstack = ptmp;
		_size *= 2;
	}
};

int main(void)
{
	//1.开辟内存 2.调用构造函数
	SeqStack s;//
	//s.init(5);//对象成员的初始化操作
	for (int i = 0; i < 15; ++i)
	{
		s.push(rand() % 10);
	}
	while (!s.empty())
	{
		cout << s.top() << " " << endl;
		s.pop();
	}
	s.~SeqStack();//析构函数调用以后,我们说对象不存在了
	s.pop();
	SeqStack* ps = new SeqStack(60);// malloc  SeqStack(60)
	ps->push(70);
	ps->push(80);
	ps->top();
	cout << ps->top() << endl;
	delete ps;//先调用ps->~SeqStack()+然后free(ps) delete和free的区别? delete释放对象的内存并且调用析构函数,free只释放对象的堆内存
	//s.release();//释放外部成员的堆内存
	return 0;
}

3. 深拷贝和浅拷贝(普通赋值与赋值重载)

#include <iostream>
using namespace std;
//对象的深拷贝和浅拷贝
//OOP实现一个顺序栈
//构造函数和析构函数
//this指针=》类-》很多对象 共享一套成员方法
//成员方法,方法的参数都会添加一个this指针
//构造函数:
//	定义对象时,自动调用的,可以重载的;构造完成,对象产生了
//析构函数:
//	不带参数,不能重载,只有一个析构函数;析构完成,对象就不存在了,内存还存在
//.data对象
//heap new delete
//stack
//对象的深拷贝和浅拷贝
class SeqStack
{
public:
	//构造函数
	SeqStack(int size = 10) :_top(-1), _pstack(new int[size]), _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)
	{
		//防止自赋值
		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];//把原来的东西拷贝给我新的内存
		}
		delete[]_pstack;//删除原来的空间
		_pstack = ptmp;
		_size *= 2;
	}
};
int main(void)
{
	{
		SeqStack s;//没有提供任何构造函数的时候,会为你生成默认构造和默认析构函数
		SeqStack s1(10);
		SeqStack s2 = s1;// 1.调用默认的拷贝构造函数,做的是内存的数据拷贝,关键是对象如果占用外部资源,那么浅拷贝就出现问题了
		//SeqStack s2 = s1;// 2.
		//s2.operator=(s1)
		//void operator =(const SeqStack &src)
		s2 = s1;//默认的赋值函数=》做直接的内存拷贝
	}

	return 0;
}

		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];//把原来的东西拷贝给我新的内存
		}
		delete[]_pstack;//删除原来的空间
		_pstack = ptmp;
		_size *= 2;
	}
};

4. 类和对象代码应用实践

(1)实现一个字符串

#include <iostream>
using namespace std;
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];
			*m_data = '\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;
		}


		delete[] m_data;

		m_data = new char[strlen(other.m_data) + 1];
		strcpy(m_data, other.m_data);

		return *this;
	}//赋值重载函数
private:
	char* m_data{ nullptr };
};
int main(void)
{
	//调用带const char*参数的构造函数
	String str1;
	String str2("hello");
	String str3 = "world";

	//调用拷贝构造函数
	String str4 = str3;
	String str5(str3);
	//调用赋值重载函数
	str3 = str1 = str2;
	return 0;
}

(2)实现一个循环队列

#include <iostream>
using namespace std;
//循环队列 memcpy realloc
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(void)
	{
		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;
	}
	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;
	}
private:
	int* _pQue;//申请队列的数组空间
	int _front;//指示队头的位置
	int _rear;//指示队尾的位置
	int _size;//队列扩容的总大小
};
int main(void)
{
	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;
}

5. 初始化列表

可以指定当前对象成员变量的初始化方式,尤其是对于成员对象来说,你不这么写可能还会报错。

初始化列表与写到函数体里的区别:

写到初始化列表里面相当于int _amount = a;在定义的时候直接进行了初始化。

而把它写在构造函数的函数体里面相当于int _amount;amount = a;先定义一个_amount,然后再把a的值赋值给amount。

对于简单类型,打开反汇编可以看到它们的指令是一样的,对于成员对象,这样写相当于先定义了一个CDate _date,然后对_date里的成员一一赋值。因为我没有提供默认构造,所以就会报错。

6. 类的各种成员方法以及区别

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

普通的成员方法 => 编译器会添加一个this形参变量(静态对象无法调用)

1.属于类的作用域

2.调用该方法时,需要依赖一个对象

3.可以任意访问对象的私有成员

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

1.属于类的作用域

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

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

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

1.属于类的作用域

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

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

常对象只能调用常成员方法,所以当我们写一个函数只有读操作的时候,最好将它实现成const成员方法

#include <iostream>
using namespace std;
//类的各种成员-成员方法/变量
// 普通成员方法=》编译器会添加一个this形参变量
// 1.属于类的作用域
// 2.调用该方法时,需要依赖一个对象(常对象是无法调用的  实参:const CGoods*  形参:CGoodds *this)
// 3.可以任意访问对象的私有成员变量
//
// static静态成员方法=》不会生成this形参
// 1.属于类的作用域
// 2.用类名作用域调用方法
// 3.可以任意访问对象的私有成员,仅限于不依赖对象的成员(只能调用其他的static成员)
//
// const 常成员方法-》const CGoods *this
// 1.属于类的作用域
// 2.调用依赖一个对象,普通对象或者常对象都可以
// 3.可以任意访问对象私有成员,但是只能读,不能写,也只能调用常方法
//日期类
class CDate
{
public:
	CDate(int y, int m, int d)//自定义了一个构造函数,编译器就不会再产生默认构造了
	{
		_year = y;
		_month = m;
		_day = d;
	}
	void show() const
	{
		cout &lt;&lt; _year &lt;&lt; &quot;/&quot; &lt;&lt; _month &lt;&lt; &quot;/&quot; &lt;&lt; _day &lt;&lt; endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
//构造函数的初始化列表
//CDate信息 CGoods商品信息的一部分 a part of...组合的关系
class CGoods
{
public:
	CGoods(const char* n, int a, double p,int y, int m, int d) :_date(y, m,d)//1.构造函数的初始化列表
	{
		//2.当前类类型构造函数体
		strcpy(_name, n);
		_amount = a;
		_price = p;
		_count++;
	}
	//普通的成员方法
	void show() //打印商品的私有的信息 CGoods *this
	{
		cout &lt;&lt; &quot;name:&quot; &lt;&lt; _name &lt;&lt; endl;
		cout &lt;&lt; &quot;amount:&quot; &lt;&lt; _amount &lt;&lt; endl;
		cout &lt;&lt; &quot;price:&quot; &lt;&lt; _price &lt;&lt; endl;
		_date.show();
	}
	//常成员方法 只要是只读操作的成员方法,一律实现成const常成员方法
	void show() const//打印商品的私有的信息 CGoods const *​**this
	{
		cout &lt;&lt; &quot;name:&quot; &lt;&lt; _name &lt;&lt; endl;
		cout &lt;&lt; &quot;amount:&quot; &lt;&lt; _amount &lt;&lt; endl;
		cout &lt;&lt; &quot;price:&quot; &lt;&lt; _price &lt;&lt; endl;
		_date.show();
	}
	//静态的成员方法
	static void  showCGoodsCount()//打印所有商品共享的信息 没有this指针的
	{
		cout &lt;&lt; &quot;所有商品的种类数量是:&quot; &lt;&lt; _count &lt;&lt; endl;
		//cout &lt;&lt; &quot;name:&quot; &lt;&lt; _name &lt;&lt; endl;
	}
private:
	char _name[20];
	int _amount;
	double _price;
	CDate _date;//成员对象 1.分配内存 2.调用构造函数
	static int _count;//不属于对象,而是属于类级别的 声明 用来记录商品对象的总数量
};
//static成员变量一定要在类外进行定义并且初始化
int CGoods::_count = 0;
int main(void)
{
	CGoods good1(&quot;商品1&quot;,100,35.0,2019,5,12);
	good1.show();
	CGoods good2(&quot;商品2&quot;, 100, 35.0, 2019, 5, 12);
	good2.show();
	CGoods good3(&quot;商品3&quot;, 100, 35.0, 2019, 5, 12);
	good3.show();
	CGoods good4(&quot;商品4&quot;, 100, 35.0, 2019, 5, 12);
	good4.show();
	//good4.showCGoodsCount();
	CGoods::showCGoodsCount();
	const CGoods good5(&quot;非卖品&quot;, 100, 35.0, 2019, 5, 12);
	good5.show();//CGoods::show(&amp;good5) const CGoods**​*-&gt;const CGoods*this
	return 0;
}

7. 指向类成员的指针

#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(void)
{
	Test t1;
	Test* t2 = new Test();
	//指向成员方法的指针
	void (Test:: * pfunc)() = &Test::func;
	(t1.*pfunc)();
	(t2->*pfunc)();

	//如何定义函数指针指向类的static成员方法呢?
	void (*pstatic_func)() = &Test::static_func;
	(*pstatic_func)();
	(*pstatic_func)();
#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
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值