编译器默认的拷贝构造函数,是发生的浅拷贝,像指针的赋值就会让指针指向同一个地址空间,析构时就会对同一个地址空间释放两次,就会造成程序崩溃.
自定义在模板内的拷贝构造函数:
Queue(const Queue<T> &src)//类对象的拷贝构造函数
{
//Queue();
_pfirst = _prear = NULL;
QueueItem*p =src._pfirst;
while (p != NULL)
{
addQue(p->_data);
p = p->_pnext;
}
}
上述拷贝构造函数仅仅支持同种类型的对象之间的拷贝构造,对于不同类型的对象之间的拷贝构造就需要建立如下模板(但是必须在定义友元类):
在private中需要先定义如下:
template<typename E>
friend class Queue;
template<typename E>
Queue(const Queue<E>&src)//自定义拷贝构造函数的模板,Queue<E>为新类型,必须先声明Queue<E>类类型为此类型的友元类型,此模板不能替代上述同类型的拷贝构造
{
cout << "const Queue<E>& 模板" << endl;
_pfirst = _prear = NULL;
Queue<E>::QueueItem*p = src._pfirst;//必须加Queue<E>这个作用域,否则指针的类型不一样,会出现错误。
while (p != NULL)
{
addQue(p->_data);
p = p->_pnext;
}
}
此模板在模板外定义:
//不同类型对象的拷贝构造函数的模板外定义
template<typename T>
template<typename E>
Queue<T>::Queue(const Queue<E> &src)
{
Queue<E>::QueueItem*p = src._pfirst;
while (p != NULL)
{
addQue(p->_data);
p = p->_pnext;
}
}
此支持不同类型对象之间的拷贝构造函数不能替代同种类型对象的的拷贝构造函数。
赋值运算符同样需要自定义,否则就会出现和拷贝构造相同的问题,自定义的相同类型的对象之间的赋值运算符重载函数:
void operator=(const Queue<T> &src)//自定义的赋值运算符的重载函数,避免了编译器默认的浅拷贝,造成的内存泄漏等问题
{
cout << "operator Queue<T> &src" << endl;
if (this == &src)
{
return;
}
if (_pfirst != NULL)
{
while (_pfirst != _prear)
{
QueueItem*tmp = _pfirst->_pnext;
delete _pfirst;
_pfirst = tmp;
}
}
delete _pfirst;
_pfirst = _prear = NULL;//必须将头尾指针指向NULL,否则就会从_pfirst的位置向后添加元素,而_pfirst的位置确是已经释放的随机值
QueueItem*p = src._pfirst;
while (p != NULL)
{
addQue(p->_data);
p = p->_pnext;
}
}
不同类型对象之间的赋值运算符的重载函数模板:
template<typename E>
void operator=(const Queue<E> &src)//不同类型对象之间的赋值运算
{
cout << "operator Queue<T> &src模板" << endl;
if (_pfirst != NULL)
{
while (_pfirst != _prear)
{
QueueItem*tmp = _pfirst->_pnext;
delete _pfirst;
_pfirst = tmp;
}
}
delete _pfirst;
_pfirst = _prear = NULL;
Queue<E>::QueueItem*p = src._pfirst;
while (p != NULL)
{
addQue(p->_data);
p = p->_pnext;
}
}
在没有给定此模板时,此句int_queue = double_queue会先调用不同类型对象直接的拷贝构造函数先生成同种类型得临时对象,再调用同种类型的赋值运算符的重载函数赋值成功,当定义了此 模板就直接实例化此模板一次就完成赋值。
主函数:
int main()
{
Queue<int> int_queue;
int_queue.addQue(10);
int_queue.addQue(20);
Queue<double> double_queue = Queue<double>();
double_queue.addQue(30.5);
Queue<int> int1_queue(int_queue);//相同类型对象之间的拷贝构造,需要自定义拷贝构造函数,否则编译器默认的造成浅拷贝(指针的赋值)导致出错
int1_queue.addQue(40);
Queue<int> int2_queue(double_queue);//不同类型对象之间的拷贝构造,编译器不会产生,需要自定义。
cout <<"int_queue------------------------------------------" << endl;
int_queue.show();
cout << "int1_queue----------------------------------------" << endl;
int1_queue.show();
cout << "double_queue--------------------------------------" << endl;
double_queue.show();
cout << "int2_queue----------------------------------------" << endl;
int2_queue.show();
cout << "赋值运算符的重载函数---------------------------------------------" << endl;
//int_queue = int1_queue;
//int_queue = Queue<int>(int1_queue);
//int_queue = double_queue;在没有给定不同类型的对象之间的赋值运算符的重载函数时,编译器会先调用不同类型对象的拷贝构造函数
//将double类型的对象构造成Int类型的临时对象,在调用相同类型对象之间的赋值运算符赋值给int_queue
int_queue = Queue<double>(double_queue);
int_queue.show();
return 0;
}
运行结果:
Visual Leak Detector Version 2.4RC2 installed.
const Queue& 模板
int_queue——————————————
10 20
int1_queue—————————————-
10 20 40
double_queue————————————–
30.5
int2_queue—————————————-
30
赋值运算符的重载函数———————————————
operator Queue &src模板
30
No memory leaks detected.
Visual Leak Detector is now exiting.
请按任意键继续…