关于类的一些疑问

sxqinge 2014-09-02 02:40:26
因为基础薄弱,在补习类的深复制/浅复制这节中,自己写了个测试程序,由此引发了几个疑问,希望大侠们帮我解答下,先上代码:

#include <iostream>

using namespace std;
class test{
public:
int *p;
test(int value){
p = new int(value);
}
~test(){
delete p;
p = NULL;
}

test operator = (const test &pt){
printf("\n test.");
if( p != NULL ){
delete [] p;
p = NULL;
}

p = new int(*pt.p);
memcpy(p,&pt,sizeof(pt));
return *this;
}

friend ostream & operator << ( ostream &os, test &A ){
os << *A.p;
return os;
}
void printvalue(){
cout<<"the value is "<<*p<<endl;
}
};

void func(test &t){
cout<<"in the func value is "<< t <<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
test t1 = 33;
test t2 = t1;
func(t1);
t2.printvalue();
system("pause");
return 0;
}


疑问如下:
1、void func(test &t)。如果参数不加引用,则执行完该函数后,就直接跳入test的析构函数去了,加了引用符号就不会被析构。这里我不能理解,func函数里面传入的是t1的变量,t1生命周期并未结束,为什么会被析构呢?对于函数参数加引用,我以前一般当还需要取回该运算结果才加,一般情况下都不加的;
2、test类我已经重载了=运算了,但是在main里面执行t2=t1时,调试发现并未进入重载=的函数中。这里是不是我重载函数没有写对呢?
3、因为第2步的原因,我这里没有执行重载=的运算,事实上执行t2=t1时就是浅复制操作了,所以在程序退出时会进行两次析构操作,第二次析构时,因为原来指针已被释放,再次执行析构时就会发生错误。

我的问题就是如上2点概述,希望大侠们能抽空帮我补习下涉及的知识,谢谢了。
...全文
312 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
sxqinge 2014-09-02
  • 打赏
  • 举报
回复
引用 20 楼 M_HANDLE 的回复:
恩,目测这次应该没啥问题的,不过operator = 一般返回引用比较好
呵呵分数少了,所以平摊下来没多少分咯。再次谢谢你的解答。 刚开始复制函数我是返回引用的,在网上看了下说类里面尽量少用返回引用,我就把它给去掉了。
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
引用 19 楼 sxqinge 的回复:
在大家的指导下,我最终的代码分享如下,再次感谢大家的热心帮助:

#include <iostream>

using namespace std;
class test{
public:
	int *p;
	test(int value){
		p = new int(value);
	}
	~test(){
		delete p;
		p = NULL;
	}

	test(const test &other){
		p = new int(*other.p);
	}
	
	test operator = (const test &pt){
		if( this == &pt ) return *this;		
		delete p;
		p = new int(*pt.p);
		return *this;
	}

	bool operator == (const test &other){
		return p == other.p;
	}

	friend ostream & operator << ( ostream &os, test &A ){
		os << *A.p;
		return os;
	}
	void printvalue(){
		cout<<"the value is "<<*p<<endl;
	}
};

void func(test t){
	cout<<"in the func value is "<< t <<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	test t1 = 33;
	test t2 = t1;
	t2 = 45;
	func(t1);
	t1.printvalue();
	system("pause");
	return 0;
}
operator应该返回&,否则你无法写出这样的代码: test t,t1,t2; t = t1 = t2;
M_HANDLE 2014-09-02
  • 打赏
  • 举报
回复
恩,目测这次应该没啥问题的,不过operator = 一般返回引用比较好
sxqinge 2014-09-02
  • 打赏
  • 举报
回复
在大家的指导下,我最终的代码分享如下,再次感谢大家的热心帮助:

#include <iostream>

using namespace std;
class test{
public:
	int *p;
	test(int value){
		p = new int(value);
	}
	~test(){
		delete p;
		p = NULL;
	}

	test(const test &other){
		p = new int(*other.p);
	}
	
	test operator = (const test &pt){
		if( this == &pt ) return *this;		
		delete p;
		p = new int(*pt.p);
		return *this;
	}

	bool operator == (const test &other){
		return p == other.p;
	}

	friend ostream & operator << ( ostream &os, test &A ){
		os << *A.p;
		return os;
	}
	void printvalue(){
		cout<<"the value is "<<*p<<endl;
	}
};

void func(test t){
	cout<<"in the func value is "<< t <<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
	test t1 = 33;
	test t2 = t1;
	t2 = 45;
	func(t1);
	t1.printvalue();
	system("pause");
	return 0;
}
M_HANDLE 2014-09-02
  • 打赏
  • 举报
回复
引用 15 楼 sxqinge 的回复:
另外对于函数void func(test t),如果不加引用的话,传入的t1就会被delete掉。比如下段代码:

test t1 = 33;
test t2 = t1;
t2 = 45;
func(t1);
t1.printvalue(); //此时打印会发现值为个很大的负数。
所以对于是否加引用的方法我还是不明白,按理来说,不加引用我只是传入值的,为什么会把t1指针给删掉了呢?奇怪的是虽然它被删掉了,但是析构里面的NULL赋值却未执行。
不加引用func形参t的构造采用默认复制构造函数,会执行t.p = t1.p,t1析构时会执行delete p,这时删掉的是p指向的内存,因为t1的p指向的内存和t的p指向的内存是同一块内存,所以t1的p指向的内存也被删掉了,你再输出就出错了。另外不加引用NULL赋值会执行的,你确定没加引用?
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
引用 16 楼 passion_wu128 的回复:
[quote=引用 15 楼 sxqinge 的回复:] 另外对于函数void func(test t),如果不加引用的话,传入的t1就会被delete掉。比如下段代码:

test t1 = 33;
test t2 = t1;
t2 = 45;
func(t1);
t1.printvalue(); //此时打印会发现值为个很大的负数。
所以对于是否加引用的方法我还是不明白,按理来说,不加引用我只是传入值的,为什么会把t1指针给删掉了呢?奇怪的是虽然它被删掉了,但是析构里面的NULL赋值却未执行。
你的operator错误很多,为什么要把pt delete掉呢?而且delete之后又去取值,给你个参考:

	test& operator=(const test& pt)
	{
		if(*this == pt)
		{
			return *this;
		}
		p = new int(*(pt.p));

		return *this;
	}

	bool operator==(const test& pt)
	{
		return p == pt.p;
	}
按这个代码调试就不会有问题了。[/quote] 我看错了,要delete自己的p

	test& operator=(const test& pt)
	{
		if(*this == pt)
		{
			return *this;
		}
		//C++标准规定可以delete空指针,不用判断是否为空
		delete p;

		p = new int(*(pt.p));

		return *this;
	}
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
引用 15 楼 sxqinge 的回复:
另外对于函数void func(test t),如果不加引用的话,传入的t1就会被delete掉。比如下段代码:

test t1 = 33;
test t2 = t1;
t2 = 45;
func(t1);
t1.printvalue(); //此时打印会发现值为个很大的负数。
所以对于是否加引用的方法我还是不明白,按理来说,不加引用我只是传入值的,为什么会把t1指针给删掉了呢?奇怪的是虽然它被删掉了,但是析构里面的NULL赋值却未执行。
你的operator错误很多,为什么要把pt delete掉呢?而且delete之后又去取值,给你个参考:

	test& operator=(const test& pt)
	{
		if(*this == pt)
		{
			return *this;
		}
		p = new int(*(pt.p));

		return *this;
	}

	bool operator==(const test& pt)
	{
		return p == pt.p;
	}
按这个代码调试就不会有问题了。
sxqinge 2014-09-02
  • 打赏
  • 举报
回复
另外对于函数void func(test t),如果不加引用的话,传入的t1就会被delete掉。比如下段代码:

test t1 = 33;
test t2 = t1;
t2 = 45;
func(t1);
t1.printvalue(); //此时打印会发现值为个很大的负数。
所以对于是否加引用的方法我还是不明白,按理来说,不加引用我只是传入值的,为什么会把t1指针给删掉了呢?奇怪的是虽然它被删掉了,但是析构里面的NULL赋值却未执行。
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
Sorry,我引用错了,我是想引用我2楼的回答。 因为operator=里面要判断*this==pt,所以要定义operator==
sxqinge 2014-09-02
  • 打赏
  • 举报
回复
非常感谢大家对我的解答。刚开始是理解错了,把复制函数理解为了拷贝构造函数,我另外写了段拷贝构造函数如下:

test(const test &other){
		p = new int(*other.p);
	}
另外按照各位的方法,先定义了test t2(0);然后在执行t2 = t1;就进入复制函数了。基本要求已经达到。 但是对于楼上的说法:
引用 12 楼 passion_wu128 的回复:
[quote=引用 1 楼 shiguojie19892 的回复:]
    ~test(){
        delete p;
        p = NULL;
    }
申请的int(value) 释放应该加:delete[] p 吧?
这个代码编译不过应该再定义operator==

bool operator == (const test& pt)
{
	return p == pt.p;
}
[/quote] 我不明白,为什么执行p = NULL,还要重载==呢?
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
引用 1 楼 shiguojie19892 的回复:
    ~test(){
        delete p;
        p = NULL;
    }
申请的int(value) 释放应该加:delete[] p 吧?
这个代码编译不过应该再定义operator==

bool operator == (const test& pt)
{
	return p == pt.p;
}
勤奋的小游侠 2014-09-02
  • 打赏
  • 举报
回复
引用 9 楼 passion_wu128 的回复:
[quote=引用 6 楼 lovesmiles 的回复:] 问题1 函数参数不加引用,意思是值传递,也就是说函数内部会复制一个监时的参数。 func函数里面传入的是t1的变量,t1生命周期并未结束,为什么会被析构呢? t1从未被func函数析构,你看到的析构是因为非引用传参,造成了函数内复制临时变量--这个复制过程调用的是一个编译器自己生成的拷贝构造函数来完成的,函数结束后这个临时变量被析构。 问题2 test t1 = 33; test t2 = t1; 这两种方法并不能调用=运算符.上面两种操作,第一种调用的是test(int value)构造函数,将33构造成test,第二种调用的是拷贝构造函数。 什么时候才能真正调用=运算符?答案是这个类已经构造完成的情况,像下面这样: test t2; //调用默认构造函数构造t2 t2 = t1; //因为t2已经构造完成,所以这里调用的就是=运算符了。 问题3 你的代码显然是缺少一个拷贝构造函数: test ::test (const test &pt)//在这个函数内部完成深复制。 建议楼主搜一下 copy构造函数和赋值构造函数 的异同。
楼主的代码里哪有默认构造函数? 写test t2; 会编译失败。[/quote] 你是对的,但我的内容的重点不是在有没有默认构造函数这里面。
mujiok2003 2014-09-02
  • 打赏
  • 举报
回复
加上拷贝构造函数再说
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
引用 6 楼 lovesmiles 的回复:
问题1 函数参数不加引用,意思是值传递,也就是说函数内部会复制一个监时的参数。 func函数里面传入的是t1的变量,t1生命周期并未结束,为什么会被析构呢? t1从未被func函数析构,你看到的析构是因为非引用传参,造成了函数内复制临时变量--这个复制过程调用的是一个编译器自己生成的拷贝构造函数来完成的,函数结束后这个临时变量被析构。 问题2 test t1 = 33; test t2 = t1; 这两种方法并不能调用=运算符.上面两种操作,第一种调用的是test(int value)构造函数,将33构造成test,第二种调用的是拷贝构造函数。 什么时候才能真正调用=运算符?答案是这个类已经构造完成的情况,像下面这样: test t2; //调用默认构造函数构造t2 t2 = t1; //因为t2已经构造完成,所以这里调用的就是=运算符了。 问题3 你的代码显然是缺少一个拷贝构造函数: test ::test (const test &pt)//在这个函数内部完成深复制。 建议楼主搜一下 copy构造函数和赋值构造函数 的异同。
楼主的代码里哪有默认构造函数? 写test t2; 会编译失败。
半醉看夕阳 2014-09-02
  • 打赏
  • 举报
回复
1:如果不加引用,就是传的参数的副本,函数调用结束,肯定会调用析构函数去析构那个副本; 2:test t2 = t1; 怎么会调用赋值函数?它会调用拷贝构造函数(用一个已存在的对象去初始化一个正在创建的对象,会调用拷贝构造函数)。
M_HANDLE 2014-09-02
  • 打赏
  • 举报
回复
先回答你第一问,t1确实没有析构,析构的是fun的形参t,t1赋值给t,t也是类test的对象,生命周期结束当然会执行类test 的析构函数。 第二个问题: test t2 = t1; 这句是初始化,不是赋值,所以不会调用operator =,调用的是默认的复制构造函数,由于test类里有指针,所以最好重新定义复制构造函数来实现指针成员的深拷贝。一定要弄清楚初始化和赋值的区别,初始化只能有一次(和定义一起),而赋值可以有多次。 至于第三问,你知道啥原因,就不说了
勤奋的小游侠 2014-09-02
  • 打赏
  • 举报
回复
问题1 函数参数不加引用,意思是值传递,也就是说函数内部会复制一个监时的参数。 func函数里面传入的是t1的变量,t1生命周期并未结束,为什么会被析构呢? t1从未被func函数析构,你看到的析构是因为非引用传参,造成了函数内复制临时变量--这个复制过程调用的是一个编译器自己生成的拷贝构造函数来完成的,函数结束后这个临时变量被析构。 问题2 test t1 = 33; test t2 = t1; 这两种方法并不能调用=运算符.上面两种操作,第一种调用的是test(int value)构造函数,将33构造成test,第二种调用的是拷贝构造函数。 什么时候才能真正调用=运算符?答案是这个类已经构造完成的情况,像下面这样: test t2; //调用默认构造函数构造t2 t2 = t1; //因为t2已经构造完成,所以这里调用的就是=运算符了。 问题3 你的代码显然是缺少一个拷贝构造函数: test ::test (const test &pt)//在这个函数内部完成深复制。 建议楼主搜一下 copy构造函数和赋值构造函数 的异同。
熊熊大叔 2014-09-02
  • 打赏
  • 举报
回复
2. 你需要实现一个test(test &pt)函数
passion_wu128 2014-09-02
  • 打赏
  • 举报
回复
引用 1 楼 shiguojie19892 的回复:
    ~test(){
        delete p;
        p = NULL;
    }
申请的int(value) 释放应该加:delete[] p 吧?
new 对应 delete,new[] 才对应 delete[]
熊熊大叔 2014-09-02
  • 打赏
  • 举报
回复
1. void func(test &t)是传引用。 void func(test t)是传值,调用的时候会新创建一个t出来并把实参复制过来,所以函数退出的时候要把这个自动创建的参数t释放掉
加载更多回复(2)

64,632

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧