关于构造函数的问题
我有C++类:
class test
{
public:
test();
test(int i);
private:
int _i;
};
有如下三个问题:
test::test()
{
this->test(9);
}
为何上一步不能编译通过?
test::test()
{
test::test(9);
}
为何不能得到正确的结果?
test::test()
{
this->test::test(9);
}
为何能得到正确的结果?
请讲述具体的原理,不胜感激!!!!!!
问题点数:0、回复次数:29Top
1 楼lifeixiao(李飞笑)回复于 2004-09-03 15:45:04 得分 0
markTop
2 楼plainsong(短歌)()回复于 2004-09-03 16:00:18 得分 0
我觉得这三种形式都应该是语法错误。构造函数不是test的成员函数,不能这样调用,只能在对象初始化时使用。可以编译的两种形式应该是编译器没有考虑到。
要实现你要的目的,应该只写一个构造函数:
class test
{
public:
test(int i = 9);
private:
int _i;
};
Top
3 楼iorchis(江楠)回复于 2004-09-03 16:15:10 得分 0
test::test()
:_i(9) //如欲将_i设为定值9
{
...
}
test::test(int i)
:_i(i) //如欲用传入的参数设定_i的值
{
...
}
Top
4 楼wwwooowww(熔点)回复于 2004-09-03 16:16:28 得分 0
我不知道你用的什么编译器,我在.net下时都有错误。
1、test::test()
{
this->test(9);
}
错误的原因:你的对象还没有构造,所以this指针没有指向。因为this是指向该类对象的指针,该类对象没有生成,故指针没有指向。
2、test::test()
{
test::test(9);
}
这样的用法只有类的静态成员才可以使用。你的构造函数不是静态的,所以错误。
而且调用一个类的函数,除了静态函数,和构造函数,都是某个对象调用的,也就是说都省略了this指针。在你的对象没有构造前,指针是错误的。
3、test::test()
{
this->test::test(9);
}
这个错误是前俩种的综合。我觉得不对。
Top
5 楼freshairfly(无知的虾米)回复于 2004-09-03 16:35:00 得分 0
不同意 plainsong(短歌) 的“构造函数不是test的成员函数” 这句话
Top
6 楼coolrick(拎壶冲)回复于 2004-09-03 16:40:40 得分 0
试试这样
test():test(9){}Top
7 楼wangyupacket()回复于 2004-09-03 16:42:25 得分 0
我觉得你们说的不对。
通过在构造函数中打印this指针和对象的地址比较,结果是一致的。说明在构造函数以前,this指针就已经建立。利用this->test::test(9),确实能达到类似于java中构造函数相互调用的目的。但是原理何在??
我的编译环境是VC++6.0Top
8 楼beyondtkl(大龙驹<*好久没来了,兄弟们好吧。*>)回复于 2004-09-03 16:42:44 得分 0
构造函数不是我们 在外面直接 显式调用的
而是 compiler调用的.
短歌说的 构造函数不是test的成员函数也就是这个意思..是成员函数的话 我们的对象就可以显式调用..Top
9 楼plainsong(短歌)()回复于 2004-09-03 16:47:22 得分 0
wwwooowww判断它们是语法错误是正确的,但理由是错误的。
>test::test()
>{
> this->test(9);
>}
>错误的原因:你的对象还没有构造,所以this指针没有指向。因为this是指向该类对象的指
>针,该类对象没有生成,故指针没有指向。
在构造函数和析构函数中使用this是完全可以的,有些对象会在构造时把自己注册到某一个全局容器中而在析构时注销,这种作法是安全的。事实上在构造函数的函数体中的语句执行时,不仅this有效,this所指向的该类的数据成员也都已经构造完毕,可以通过this去访问:
class test
{
int i;
public:
test(int init_i):i(init_i){cout << this-> i;}//这里没什么问题。
};
>2、test::test()
>{
> test::test(9);
>}
>这样的用法只有类的静态成员才可以使用。你的构造函数不是静态的,所以错误。
>而且调用一个类的函数,除了静态函数,和构造函数,都是某个对象调用的,也就是说都省
>略了this指针。在你的对象没有构造前,指针是错误的。
错。在非静态成员函数中用class::member的方式访问非静态成员函数是可以的,这时会把当前的this指针传进去:
class test
{
int _i;
void set_i(int i){ _i = i;}
public:
test(){ test::set_i(0);}
};
这种方法通常用于在基类同名成员函数被衍生类重载(overload)时来指明调用的是基类的成员函数,或是用来在调用虚成员阻止多态行为。而如果class就是当前的类,而mamber不是虚成员,它就相当于直接调用member。在本例中就相当于test(){set_i(0);}
两个理由都不正确,当然也就没有什么“综合”了。
其实正确的理由是:构造函数不能直接访问。构造函数没有名字,所以在编译this->test(9)或是test::test(9)时,编译器无法在test这个类的成员名字列表中找到它。错误提示信息应该是:“test不是test的成员”。
ISO/IEC 14883:1988 12.1.2
A constructor is used to initialize objects of its class type. Because constructors do not have names, the are never found during name lookup;……Top
10 楼beyondtkl(大龙驹<*好久没来了,兄弟们好吧。*>)回复于 2004-09-03 16:47:47 得分 0
回复人: coolrick(拎壶冲) ( ) 信誉:100 2004-09-03 16:40:00 得分: 0
试试这样
test():test(9){}
// 这样也达不到你的要求的 呵呵 因为这样是构造出一个临时对象 而不是你真正要构造的thisTop
11 楼freshairfly(无知的虾米)回复于 2004-09-03 16:51:27 得分 0
1、test::test()
{
this->test(9);
}
错误的原因:你的对象还没有构造,所以this指针没有指向。因为this是指向该类对象的指针该类对象没有生成,故指针没有指向。
-------------------------------------------------------------------------
该类的对象并不是“没有生成”而是“没有完全生成”。而“没有完全生成”并不意味着“什么都没有”。并且它是有指向的,比如:
this->_i = 9; //OK(就等价于 _i = 9; 嘛,当然可以,呵呵)
不过因为“没有完全生成”所以使用起来要小心
2、test::test()
{
test::test(9);
}
这样的用法只有类的静态成员才可以使用。你的构造函数不是静态的,所以错误。
而且调用一个类的函数,除了静态函数,和构造函数,都是某个对象调用的,也就是说都省略了this指针。在你的对象没有构造前,指针是错误的。
-------------------------------------------------------------------------
并不是只有类静态成员才可以这样使用,这个用法无非是指明一个类域,因为在test类里,默认的类域就是test::,所以没必要,至于为什么不对呢,我猜测是因为test(int i)这个构造函数还没有生成。(有点编译器可能这样用法不规范,所以认为是错误的,但有的编译器是不报错的,比如VC6.0和Dev C++4.9.6.0)
至于第三种为什么正确了呢?实在是想不出来为什么(可能是不同编译器实现手法不一样吧,VC6.0上是可以的并且是正确的,Dev C++4.9.6.0就编译通不过了)。Top
12 楼xteaj(半桶水)回复于 2004-09-03 17:02:59 得分 0
构造函数是一种很特殊的成员函数。你注意到了没有,构造函数没有返回类型,
void也不是,因为构造函数实际上是一段类似inline函数的东西,直接插入函数
所在位置,不过因为你不能直接往对象私有成员写数据,而构造函数可以。所以
构造函数并没有实际的地址,某种意义上说,连函数都不能算。Top
13 楼plainsong(短歌)()回复于 2004-09-03 17:03:39 得分 0
在Java中构造函数可以互调,这Object Pascal也可以(据说Borland参与了Java语言的设计),但这没什么必要性。你完全可以把两个构造函数都要有的代码写到一个私有的成员函数中,然后在两个构造函数中都去调用。
注意一点:C++中构造函数对基类和数据成员的构造函数的调用是强制性的,而Java和Object Pascal不是。在C++中允许构造函数互相调用必然导致对基类和数据成员的重复构造,而这将是一个灾难。
后两种方法都在VC中编译通过并且有一种可以达到楼主的目的,这并不能说明什么,只能说VC6对标准的支持不好,同时test::test()与this->test::test()得到不同的结果也是编译器的明显错误。在我BCC5.6.4中只有第二种可以通过编译,但并不能达到楼主的目的;wwwooowww说在.net都不能通过编译说明.net的编译器实现的比较出色。Top
14 楼wangyupacket()回复于 2004-09-03 17:22:17 得分 0
我觉得对象的生成可不可以这样解释:
1. test t; //为对象分配存储空间。
2.t.test() = test(t); //调用构造函数初始化对象成员。
但是我觉得test::test()好像产生了一个临时对象,这个临时对象的空间是怎样分配的?Top
15 楼plainsong(短歌)()回复于 2004-09-03 17:26:40 得分 0
我感觉不大对头。从BCBX的编译和运行结果来看,test::test()确实生成了一个临时对象,但要做到这一点正规的语法应该是test(),test::test()是解释不通的……Top
16 楼bm1408(向va_list学习~不用VC好多年~)回复于 2004-09-03 17:34:01 得分 0
构造函数我们是无法显示的调用的!Top
17 楼wangyupacket()回复于 2004-09-03 17:40:54 得分 0
使用test()或是test::test()我觉得效果应该是一样的,但关键是为什么要产生一个临时对象?而且好像不止一个编译器都是这样的!!!Top
18 楼plainsong(短歌)()回复于 2004-09-03 17:46:26 得分 0
test()和test::test()在语法上是不一样的,用test()可以定义临时对象,这里的test是类型名。用这种方法定义临时对象是很常用的手段:
class comp
{
public:
bool operator()(const string& x, const string& y)
{return x.size() < y.size();}
};
vector<string> strlist;
...
sort(strlist.begin(), strlist.end(), comp());//这里创建了一个comp类型的临时对象作为实参。
但test::test()中的test::test无论如果不能解释成一个类型:test不是一个namespace,也没有名为test的嵌套类型,那么test::test()如何解释就是一个问题了。Top
19 楼comebaby(游民)回复于 2004-09-03 18:46:40 得分 0
高深!!关注中。。。Top
20 楼nicknide(封月翔天)回复于 2004-09-03 19:50:06 得分 0
大家说了很多,我来说一个最重要的原因吧:
标准C++规则中,就不允许我们直接调用构造函数,但是可以直接调用析购函数
class A
{
public:
A();
~A();
};
A a;
a.A();//error,user cann't invoke the constant funcation
a.~A();//OK,No propram
还有,有人说是this指针的问题,其实不是,因为在调用构造函数的时候,比如VC,用ecx寄存器传过来一个this的指针,这个地址是有效的。
如果你希望实现这个this->A();这个功能,有办法的,可以这样做
#include <new>
using namespace std;
class A
{
A(){ new (this) A;}
A(int i);
};
这个定点构造的方法就可以让你随心所欲了,不过记住,这个地方的new 不是分配内存,所以绝对不能用delete删除掉,否则你自己看吧……Top
21 楼nicknide(封月翔天)回复于 2004-09-03 19:52:59 得分 0
关于定点构造,有这样一种用法:
class A
{
public:
A(const A&);
A& operator (const A& other)
{
~A();
new (this)A(other);
}
};
哈哈,不过这样做不太好哦,标准不建议这样做,虽然这样做是完全语法正确的。建议,一定不要这样哦Top
22 楼nicknide(封月翔天)回复于 2004-09-03 20:00:50 得分 0
对了,我发的第一个帖子有手误,抱歉抱歉,这里改一下,然后把例子补充完整
#include <new>
using namespace std;
class A
{
public:
A(){ new (this) A(3);}//this line is changed
A(int i):k(i){}
int k;
};
int main()
{
A a1(3);
A a2();
}
//是不是都是一样的结果了啊?
Top
23 楼renheihei(请大家注意:用DEV C++作为测试编译器!!!!!!!!!,vc++测试可能通不过!!!!!!!!)回复于 2004-09-03 20:09:42 得分 0
好问题!Top
24 楼languagec(各有所求)回复于 2004-09-03 20:40:35 得分 0
25 楼nicknide(封月翔天)回复于 2004-09-03 21:33:56 得分 0
汗,我再改(抱歉,今天有些头晕了,3天只睡了10个小时,请大家原谅了):
关于定点构造,有这样一种用法:
class A
{
public:
A(const A&);
A& operator = (const A& other)//重载等于运算
{
~A();
new (this)A(other);
}
};
Top
26 楼coyprightbao(Mr'Bao)回复于 2004-09-03 21:47:03 得分 0
markTop
27 楼BluntBlade(信仰迷离·重构之道,在于Redo/Undo之间)回复于 2004-09-03 22:42:29 得分 0
我在某本C++名著中看到
obj.A::A(); // 重新对已经存在的对象进行初始化
这样的写样,而我自己也试验过,确实可以通过编译。但楼主给出的示例就没有试验过。Top
28 楼wangyupacket()回复于 2004-09-07 17:28:30 得分 0
我觉得短歌说的重复构造是一个问题,但是也要看基类的申明情况而定。最近参阅了《深入探索C++对象模型》,觉得写得非常好。上面对构造函数有详细的说明,感兴趣的朋友可以看一看。Top
29 楼wangyupacket()回复于 2004-09-13 20:16:37 得分 0
BluntBlade(无锋之刃·只留程序不留情) 看的是哪本名著,介绍一下:)Top




