注册 登录
编程论坛 C++教室

this指针作为临时对象的困惑

love云彩 发布于 2013-06-07 00:15, 1486 次点击
#include<iostream>
using namespace std;
class Date
{
 int month,day,year;
public:
 Date(int m=0,int d=0,int y=0):month(m),day(d),yaer(y){}
 Date operator--(int);
 void display()
 {cout<<year<<" "<<month<<" "<<day<<endl;}
};
Date operator--(int)
{
  Date dt(*this);//等价于Date dt=*this语句,创建一个临时对象,然后调用拷贝构造函数
  month--;
if(month<=0)
{month+=12;--year;}
return dt;
}
void main()
{
  Date dt(12,18,2008);
  Date da;
  da=dt--;
  cout<<"da:";
  da.display();
  dt.display();
}
加颜色部分我不懂,在这里,this 指针怎么用?怎么创建一个临时对象?求解答
27 回复
#2
rjsp2013-06-07 08:26
Date dt(*this);//等价于Date dt=*this语句,创建一个临时对象,然后调用拷贝构造函数
------ “等价于Date dt=*this语句”是对的,“创建一个临时对象”是在瞎扯
#3
peach54602013-06-07 09:04
回复 2楼 rjsp
不是调用的拷贝构造么
dt是个临时变量,没错吧
#4
rjsp2013-06-07 09:37
回复 3楼 peach5460
“Date dt(*this);//等价于Date dt=*this语句,创建一个临时对象,然后调用拷贝构造函数”

这句话太难理解了,第一次回答时,我就有两种不同的理解。再看到你的回复,又是一种理解方式。
你的理解是:Date dt(*this);等价于Date dt=*this语句;Date dt(*this)创建一个临时对象,然后调用拷贝构造函数。
我当时的理解是:Date dt(*this);等价于Date dt=*this语句,内部实现过程都是 创建一个临时对象,然后调用拷贝构造函数”
                Date dt(*this);等价于Date dt=*this语句,内部实现过程唯一差别是其中某个是 创建一个临时对象,然后调用拷贝构造函数”

也就是,那个逗号前后是 并列陈述的关系,还是 互为解释的关系。
#5
rjsp2013-06-07 09:44
相比较而言,peach5460的理解是对的,我错了

昨天我去高老庄了,我姓高,不要门票 --- 通常会理解为:因为我姓高,所以才不要买门票
A: 那谁谁谁,帮我去卖张门票。B: 我姓高,不要门票 --- 通常会理解为:我有名有姓的,不要无礼地呼我为“那谁谁谁”;而且高老庄是开放式的,本就不需要门票。
#6
peach54602013-06-07 11:07
回复 5楼 rjsp
呵呵,我知道我跟你理解的差异性问题了
看来楼主的注释功底不行呐
#7
love云彩2013-06-07 11:44
回复 2楼 rjsp
Date dt(*this)这个语句,应该没有创建一个临时对象吧?我怎么弄也弄不懂,如果真的需要创建临时对象的话,这个过程是怎么发生的?
因为这个this指针是一个系统变量,不能对其进行赋值操作,所以this指针只能指向一个对象,那么this指针能不能从中读取数据?如果能,前提说了不能对this指针进行赋值操作,那就要创建一个临时对象来储存this指针所读取出来的数据。但最后又回头想了想,这个语句怎么创建临时对象啊,this指针指向一个对象,进行赋值的时候自然会调用拷贝构造函数的呀,需要临时对象吗
#8
rjsp2013-06-07 11:58
回复 7楼 love云彩
对于那段注释,你的理解和我的理解是一样的
但原作者的意思应当如三楼peach5460那么理解
#9
love云彩2013-06-07 12:28
对于那个临时对象的用法,我始终无法理解,百度找了一下,太泛了,没有我想要的答案,版主能不能就临时对象给我举几个简单的例子?
#10
love云彩2013-06-07 12:33
回复 3楼 peach5460
dt是一个对象,不是变量吧?,对象与变量之间能划上等号吗
#11
TonyDeng2013-06-07 12:44
这个代码是用来测试编译器的吧?
#12
peach54602013-06-07 12:49
以下是引用love云彩在2013-6-7 12:33:08的发言:

dt是一个对象,不是变量吧?,对象与变量之间能划上等号吗

你所谓的变量只能是int吗?
那int不是对象?
那什么是对象...
#13
love云彩2013-06-07 13:04
扯远了,回到原来的话题,按照各位所说的。总结为以下:
dt是一个临时变量,不是临时对象,不存在创建临时对象,调用拷贝构造函数。
说到这里,我只剩下那个*this不明白,不知道它是怎么运作的。莫不成就是——*this指针指向一个对象,
然后这个对象调用拷贝构造函数拷贝一份数据给dt,this的作用仅仅是表明指向一个对象吗????
#14
TonyDeng2013-06-07 13:26
其实你写这个类,省略了默认的构造函数(所调用的正是默认构造函数),你知道默认构造函数的参数是怎样的?那是复制参数还是引用参数?
#15
TonyDeng2013-06-07 13:33
C++有一点不好,就是尽管你写了自定义构造函数,但仍然有默认构造函数,除非你明显覆盖它(C#也有默认构造函数,但如果写了自定义构造函数,默认构造函数就失效)。1楼的代码,在类方法内部调用默认构造函数,但编写这个调用代码的人,恐怕都不知道默认构造函数的参数声明是引用传递还是复制传递的。

[ 本帖最后由 TonyDeng 于 2013-6-7 13:37 编辑 ]
#16
love云彩2013-06-07 13:52
说了那么久,我还是不确定this指针用来干嘛的,那个语句有没有实现了创建临时对象
如果有创建临时对象,谁起了作用?
#17
love云彩2013-06-07 14:00
回复 15楼 TonyDeng
默认构造函数也许根据编译系统的不同而不同吧!
我曾经在vs2012上面写过带有缺省参数的构造函数,只要带有
缺省值的构造函数,就被编译器系统认为是默认构造函数了!
比如Date(int m=0,int d=0,int y=0)这样的带有缺省参数的构造函数
我可以在主函数体里面成功创建一个Date a,这种情况版主见过吗?
#18
TonyDeng2013-06-07 14:06
在VC中默认构造函数的原型一般是Date(Date& d),即参数是引用,不会复制对象的,这是为防止对象不可复制而优先选择的传参方式。别的编译器我不知道,所以才在上面说你这个代码是不是要测试编译器的。但无论如何,我写这个程序都不会把结果寄托在未知的情况下,更不会这样使用*this来创建对象,宁愿自己多写一个复制重载函数也比这样写保险得多,别人也知道程序的真实运作机制。
#19
TonyDeng2013-06-07 14:11
这个自减重载写成这样,可算是没事找事,玩代码的人才会这样写吧。
#20
love云彩2013-06-07 14:38
回复 19楼 TonyDeng
那么,可以肯定的是,Date dt(*this)这个语句并没有创建临时对象,
this指针只是指向当前对象,然后就调用默认的复制构造函数将this指针所
指向的当前对象的数据拷贝一份给dt!
的确,有些时候,有些对象不能直接使用默认构造函数进行拷贝,要自己写一个拷贝构造函数,
那就是浅拷贝与深拷贝的问题了!
#21
love云彩2013-06-07 23:28
追问一个额外问题:对于临时对象,应该在哪些情况下使用到临时对象?
除了“当函数返回一个对象时,要创建一个临时对象来存放返回的对象”这种情况,还有其他什么情况??
1,当函数返回一个对象时,要创建一个临时对象来存放返回的对象(例子)
Student fn()
{
   //.....
Studnet ms("virgil")
reutnr ms;
}
int main()
{
  Student s;
  s=fn();
  return 0;
}
求版主给我列举一下其他情况下的使用临时对象的用法,如果有临时对象的概念以及例子,我就好理解了
#22
peach54602013-06-08 08:52
不明白什么叫临时对象的用法...
#23
love云彩2013-06-08 11:19
回复 22楼 peach5460
呃呃呃,就是怎么使用临时对象,什么情况下要用到临时对象
#24
peach54602013-06-08 12:45
函数里面不使用临时变量如何实现行为?
#25
TonyDeng2013-06-08 14:57
在需要的时候用上面定义的构造函数Date(year, month, day)创建一个对象即可,它是自动变量,作用期外自动消失(该类代码自己处理内存释放),这种就是临时对象,与普通变量是同样的道理(变量就是对象,C++视所处理的东西为对象,是很广泛的概念)。
#26
TonyDeng2013-06-08 22:44
程序代码:

#include <iostream>
#include <conio.h>

class Date
{
private:

    int year;
    int month;
    int day;

public:

    Date(int y = 0, int m = 0, int d = 0) : month(m), day(d), year(y) {}
    Date operator -(int days);
    void display(void);
};

void Date::display(void)
{
    std::cout << year << "-" << month << "-" << day << std::endl;
}

Date Date::operator-(int days)
{
    Date d(this->year, this->month, this->day);     // 创建临时对象
   
// 以下日期算法只作示范,具体实现你自己写
    d.day -= days;
    if (d.day < 0)
    {
        d.day += 30;
        --d.month;
    }
    return d;
}

void main(void)
{
    Date dt(2008, 12, 18);
    dt.display();
    Date d(dt - 20);
    d.display();
    _getch();
}
#27
TonyDeng2013-06-08 22:57
之所以把算符重载改为减,是因为没必要在自减中创建临时对象,那直接使用内部的year、month、day运算即可。
#28
TonyDeng2013-06-09 13:11
后缀自减的实现,必须与要求相符:在方法内部,先创建临时对象,然后使用自身的数据做减法运算(后缀自加也一样),修改数据本身,但方法返回的是临时对象,即修改前的数据。前缀自加自减才不用临时对象,所以前缀运算和后缀运算,效率是有细微差别的。
1