指针块

指针类型的函数

函数的返回值是指针(并不是说要传地址进去)
不能返回非静态的局部地址(此地址离开函数就失效了)
下面看一个合法的例子

int *search(int*a,int num)//返回的地址存放的是int型
{  for(int i=0;i<num;i++)
       if(a[i]==0)//传进来的是数组,用数组形式使用也行,但这个并不是数组,是个指针
         return &a[i];}

而动态分配的不会自动被释放,所以可以放心返回

指向函数的指针

指针容纳的是函数代码的起始地址
int(*func)(int, int)
作用:实现函数回调
在处理相似事情时可以灵活运用不同的方法
举例子:
编写一个compute函数,对整数进行各种运算,有一个形参时指向不同运算的函数,要进行不同运算,只需这个形参传的不一样即可

#include<iostream>
using namespace std;
int compute(int a, int b, int(*func)(int, int))//函数指针放到参数表中,具体用哪个函数就把哪个函数的首地址放进去
{
	return func(a, b);
}

int max(int a, int b)
{
	return (a > b ? a : b);
}
int min(int a, int b)
{
	return (a < b ? a : b);
}
int sum(int a, int b)
{
	return (a + b);
}
int main()
{
	int a = 1; int b = 2;
	int ans = compute(a, b, &max);
	cout << "max of a and b is:" << ans << endl;
	ans = compute(a, b, &min);
	cout << "min of a and b is:" << ans << endl;
	ans = compute(a, b, &sum);
	cout << "a and b is:" << ans << endl;
	return 0;

}

对象指针

指向对象的指针,指针前面的类型是类

其调用像结构体那样->

this指针

隐含于类的每一个非静态数据成员中;
指出成员函数所操作的对象
当通过一个对象成员调用函数时,系统先将该对象的地址值给this,然后调用成员函数,成员函数对对象的数据或成员进行操作时,就隐含地使用了this;
例如 point中调用getx时:
return x;
相当于return this->x;(所以我们在编写getx时觉得这个函数中并没有给x,为什么等返回x呢,就是这个原因)

在两个类的定义都用到令一个类时,把谁定义前面都不合适,我们用了前向引用声明

class A;//前向引用声明
class B
{ 
   A x;//在B中构造一个A类对象,虽然系统知道A是什么,但是不知道A具体是什么,所以不能制造A的对象,所以这样是错的
}
class A
{ 
B x;
}

我们可以用指针解决

class A;//前向引用声明
class B
{ 
   A *x;//这种情况很少,只是为了说明一下这样可行
}
class A
{ 
B x;
}

c++动态内存分配

操作符new
new+类型名T(初始化参数列表)
成功了就返回一个T类的指针,指向新分配的内存单元起始地址

delete 来删除用new申请的地址
模拟

point ptr1=new point;//申请内存并把首地址交给指针
delete ptr1;//通过指针直接释放
point prt 2=new point(1,2);//带参数申请并构造这个地址这个

申请和释放动态数组

new 类型名T[数组长度]
delete [ ]数组名T(T必须是由new构造的数组的首地址)(写方括号是释放整个数组)

point *ptr1 =new point[2];//申请一个有两个点对象的数组
int i=ptr[0].getx()//数组形式不用*
delete []ptr;//释放记得方括号

也可以分配多维数组,但是要表明长度,指针是指向数组的指针

下面是动态数组的一个例子,写的有点粗略

#include<iostream>
using namespace std;
class point//定义一个点类
{
public:

	point():x(0),y(0){}//默认构造函数
	point(int x, int y) :x(x), y(y) {}//构造函数
	point(const point& p); //赋值构造函数
	int  getX() { return x; }//对外接口
	int  getY() { return y; }
	~point() { cout << "析构了一个函数" << endl; }//析构函数
	void move(int newx,int newy)//点的移动
	{
		x=(newx);
		y=(newy);
	}
	void showpoint()//输出点
	{
		cout << "(" << x << "," << y << ")" << endl;
	}
private:
	int  x, y;
};

point::point(const point& p)//复制构造函数
{
	x = p.x;
	y = p.y;
	cout << "point复制构造函数被调用" << endl;

}

class array_of_point//动态数组类
{
public:
	array_of_point(int size) :size(size)//使points指向新分配的点内存 ,这是一个、构造函数
	{
		points = new point[size];

	}
	~array_of_point() //析构该类并把申请来的内存释放
	{ 
		cout << "析构了一个动态数组" << endl;
		delete []points;
	}
	point& element(int index)//这是一个访问数组元素的方法,为什么要引用呢,
		//因为我们想要返回的点是左值,就是可以去修改()移动它,返回类型是引用就可以做到这点,返回的是points[index]的引用,点类的引用
	{
		if(index > 0 && index < size)//防止下表越界
		return points[index];
	}
	void show(int index)//用这个指针去调用这个点的输出函数,这里无需引用
	{
		if (index > 0 && index < size)//防止下表越界
		{
			cout << "p[" << index << "]:";
			points[index].showpoint();
		}
	}
private:
	point *points;//类中的一个指针,通过它来对新申请的内存进行操作,这个成员并不需要给外部知道
	int size;//数组的大小

};
int main()
{
	int count;
	cout << "请输入点的个数:";
	cin >> count;
	array_of_point p (count);//在对象p中构造一个大小为count的数组,表示有count个点
	p.element(0).move(5,0);//调用点的移动函数实现对点的初始化,为什么要调用这个,因为在动态申请点的时候使用了默认构造函数,所以不能再用构造函数了
	p.element(1).move(10, 2);
	p.show(0);//输出前两个点
	p.show(1);

	return 0;

}

注意:这个数组是不能以下标的方式访问的,所以我们要在里面定义那么多东西来实现它的功能,而vector可以用下标方式访问

深层复制和浅层复制

若在上面主函数中改一下,构造一个与p一样的点数组p1,由于自己没有写复制构造函数,所以使用默认复制构造函数,p1中也有一个指针points,它指向的类 也是那么多,并且,它指向的地址是和p一样的地址,所以这时对p进行修改操作,也会对p1修改。
这显然不是我们想要的。
而且在释放空间时,p已经把动态内存释放,p1又去释放,就会出错。

int main()
{
	int count;
	cout << "请输入点的个数:";
	cin >> count;
	array_of_point p (count);//在对象p中构造一个大小为count的数组,表示有count个点,
	p.element(0).move(5,0);//调用点的移动函数实现对点的初始化,为什么要调用这个,因为在动态申请点的时候使用了默认构造函数,所以不能再用构造函数了
	p.element(1).move(10, 2);
	array_of_point p1(p);//复制构造一个数组
	p.show(0);//输出前两个点
	p.show(1);

	return 0;

}

针对这个问题,我们给动态数组写一个构造函数就行了:
这个就叫做深层复制。(在复制类的时候不会动用构造函数,只用复制构造函数,而这两个函数的功能不过就是把私有成员初始化等等,所以在编写构造函数时到底要干什么,就是要初始化)

array_of_point::array_of_point(const array_of_point&v)
{
size=v.size;//大小直接复制;
points=new point[size];//重新申请一个新的内存空间;
for(int i=0;i<size;i++)
    {
       point[i]=v.point[i];
    }
  
}

移动构造(c++11)

只是想把对象移动,,而不是真正想复制。即将原对象
的资源控制权全部交给目标对象
当一个对象将要消亡,且里面的内存是还要用的,我们就可以移动掉它
这样定义

array_of_point::array_of_point(const array_of_point &&v)://右值引用,直接把v的东西拿来用而不用再复制一遍,即v只放在右边
size(v.size),points(v.points)
{v.points=nullptr;}//把原指针指向空,这样以后这个原来对象消亡的话就不影响新对象那个地址,又不用构造一个新的
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值