教祖级别--复制构造函数+赋值函数

     最近是各种同学的程序,搞得前天还在实验室码了一晚上代码。渐渐的发现,一个人编代码实在是无聊,哪怕旁边有个跟我说话的银都行(耐不住寂寞~~)。

     前天的程序是个游戏,主要是给了一些基本的类接口,然后去实现。其中,对于电脑角色,涉及到博弈论,蛮好玩的,所以才决定大半夜的去把该游戏弄完。这里主要是对写的过程中遇到的老生常谈的问题,const,指针,复制构造函数+赋值函数。虽然之前也写过,查过,但就是用时有出现了世纪大bug,内存俩次释放(复制构造函数--浅复制)。

int SmartPlayerImpl::chooseMove(const Scaffold& s, int N, int color)

由于函数内部要对 s 进行某些可变操作然后再回退,所以就得对其进行复制。
Scaffold sCopy(s);

这时候就是要进Scaffold的类去看复制构造函数了!
前提:
private:ScaffoldImpl* m_impl;

(该类中存在对象/指针成员,所以要进行的是深复制)
Scaffold(const Scaffold& other); 
Scaffold& operator=(const Scaffold& rhs); 

深复制:给对象/指针开辟新空间,(如果想赋值的话,就加上值的拷贝)
Scaffold::Scaffold(const Scaffold& other)
{
    m_impl = new ScaffoldImpl(*other.m_impl);
}
赋值函数:
Scaffold& Scaffold::operator=(const Scaffold& rhs)
{
    if (this != &rhs)
    {
        Scaffold temp(rhs);
        swap(m_impl, temp.m_impl);
    }
    return *this;
}

写到这里,我以为已经ok了,然后万事大吉的开始run,每次到程序退出部分,肯定会有中断出现。然后,跟踪中断堆栈,就会发现内存还是释放了俩次,这不,再深一层:
m_impl = new ScaffoldImpl(*other.m_impl);

这不就是调用了默认的复制构造函数么,所以还是要继续实行ScaffoldImpl自己的复制构造函数:
+++++++--------+++++++---------+++++++
ScaffoldImpl::ScaffoldImpl(const ScaffoldImpl& other)
{
	m_scaffoldGrid = new int*[other.m_scaffoldRows+1];
	for(int i=0; i<other.m_scaffoldRows+1; i++)
		m_scaffoldGrid[i] = new int[other.m_scaffoldColumns+1];
	//
	for(int i=0; i<other.m_scaffoldRows+1; i++)
		for(int j=0; j<other.m_scaffoldColumns+1; j++)
			m_scaffoldGrid[i][j] = other.m_scaffoldGrid[i][j];
	//
	m_scaffoldColumns = other.m_scaffoldColumns;
	m_scaffoldRows = other.m_scaffoldRows;
	m_countEmptyNum = other.m_countEmptyNum;
	//
	m_columnHavePut = new int[m_scaffoldColumns+1];
	for(int i=0; i<m_scaffoldColumns+1; i++)
		m_columnHavePut[i] = other.m_columnHavePut[i];
}

其中,对于为什么该复制构造函数中可以调用类的私有成员,这是因为这是调用对象私有成员:

    C++的限定符是限定类的不是限定对象的,只要是类型相同就能相互访问!两个是同类型的,因此可以直接访问,但是需要指定一下是哪个对象。

    所谓访问权限(如public,private),是对“类”来说的,不是对“对象”来说的,private访问权限是其它类不能访问,而非这个类的不同对 象不能访问。 其实这也非常合理,类是自己设计的,当然自己也就知道类的内部结构,所以没有必要对自己也进行类的“封装”。 对于成员函数中允许访问对象的数据成员,一方面保证了安全性与封装性,另一方面提供方便的操作。第一句话的解释,就是承认只有成员函数可以访问私有成员, 这里不涉及友元及派生。这样一来,安全性仍然得到了保证,也完成了封装工作。对于第二句话,试想,如果都得靠接口来实现数据传送,那么操作是否极为不便?

      既然处于成员函数中,已经保证了足够的安全和封装性,那么这里如果还得借助接口,就有些不合情合理了。作为对数据成员的灵活处理,设计者允许在成员函数中 访问对象的私有成员,为使用者提供了很大的方便。这同时也反映了语言的灵活性和原则性。

OK,这个已经搞定~~
最好的办法就是:记住要实现(重载)类中的复制构造函数和赋值函数!!!

你可能感兴趣的:(复制构造函数)