还没来得及回就结了。。。

paidfighting 2008-03-17 05:11:05
基类指针指向子类对象数组的问题

http://topic.csdn.net/u/20080317/14/6bdac337-f8c1-4733-8c28-8dfae792c1b8.html

恕我挑战专家,这贴的答案是不对的啊。。。

...全文
466 61 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
61 条回复
切换为时间正序
请发表友善的回复…
发表回复
paidfighting 2008-03-19
  • 打赏
  • 举报
回复
那看来只能等老头子出这本新书了
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 48 楼 A_B_C_ABC 的回复:]
我知道不一样,但是一种变通,达到一样的效果.
[/Quote]

嗯,re
0黄瓜0 2008-03-18
  • 打赏
  • 举报
回复
我知道不一样,但是一种变通,达到一样的效果.
taodm 2008-03-18
  • 打赏
  • 举报
回复
reinterpret_cast,后果自负的运算符。
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 44 楼 A_B_C_ABC 的回复:]
引用 31 楼 Vitin 的回复:


引用 36 楼 hdt 的回复:



引用 38 楼 taodm 的回复:
《More Effective C++》item3 不要对数组使用多态.
不知道是不是和你们讨论相关。


那么当需要一个数组来使用多态时,这样应是可行的.
Base* p[N] ;
for(int i=0;i <N;++i)
{
if(i%2==0)
p[i]=new Base();
else
p[i]=new Child();
}
//....
for(int i=0;i <N;++i)
{
delete p[i]…
[/Quote]


这是指针数组,和指向数组的指针不一样
thecorr 2008-03-18
  • 打赏
  • 举报
回复
虚函数表。。。
0黄瓜0 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 Vitin 的回复:]
[/Quote]

[Quote=引用 36 楼 hdt 的回复:]

[/Quote]

[Quote=引用 38 楼 taodm 的回复:]
《More Effective C++》item3 不要对数组使用多态.
不知道是不是和你们讨论相关。
[/Quote]

那么当需要一个数组来使用多态时,这样应是可行的.
Base* p[N] ;
for(int i=0;i<N;++i)
{
if(i%2==0)
p[i]=new Base();
else
p[i]=new Child();
}
//....
for(int i=0;i<N;++i)
{
delete p[i];
}
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 42 楼 taodm 的回复:]
这么喜欢讨论“后果自负”的代码?
[/Quote]

嗯,more effective c++上有:通过一个基类指针来删除一个含有派生类对象的数组,结果将是不确定的

没有意义了,不讨论了

这种方法不能用,一用数组就要错,so。。。。我认错 - -
taodm 2008-03-18
  • 打赏
  • 举报
回复
这么喜欢讨论“后果自负”的代码?
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
然后再来看下面的例子:


class A{
int* pA;
public:
A()
{
pA = new int;
cout <<"A construct" <<endl;
}
virtual ~A()
{
cout <<"A descontruct" <<endl;
delete pA;
}
virtual void test()
{
cout <<"A test" <<endl;
}
};
class B
{
double* pB;
public:
B()
{
pB = new double;
cout <<"B construct" <<endl;
}
virtual ~B()
{
cout <<"B descontruct" <<endl;
delete pB;
}
void test()
{
cout <<"B test" <<endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{

B* b = reinterpret_cast<B*>(new A);
delete b;
}


注意,这里的代码和40楼代码的区别仅仅是B类析构函数多了个virtual,但是这里就成功析构了。

为什么?

多了个vitual实际上意味着B的对象里将含有一个虚函数表指针vfptr,这样说大家该明白了吧

A类的对象当然是含有vfptr的,40楼那里因为B类指针指向的内存将没有vfptr,所以类型信息丢失了,而这里类型信息被成功保存


所以,归根结底,并不是vs2005做的“好事”,而是虚函数表vfptr为我们提供了保证。


最后,“基类指针指向子类对象数组”这个题目可以总结为(我的观点):

可以成功的应用于抽象类中,而且是安全的,同时,也只有抽象类才能为它提供保证。另外,它只能保证正确的析构,而不是支持指针的[]操作
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 31 楼 Vitin 的回复:]
“基类指针指向子类对象数组不可以使用”这个结论是正确的。
这种行为是undefined.

比如在gcc上,当派生类(即子类)比基类占用更多的内存时,它明显将析构函数运行在了错误的内存上,从而导致程序崩溃。
而在vs2005上,只是因为编译器提供了更多的保护措施,以兼容这种错误,这并不意味者错误本身是正确的。
以下代码演示了vs2005的保护措施:

C/C++ code
#include <iostream>
using namespace std;

class B…
[/Quote]

再看这一个例子。

我要说的是,在reinterpret_cast的使用规则上,Bjarne明确的说过,除非程序员知道自己在干什么,否则不要使用reinterpret_cast

你的这个例子是说明不了问题的。reinterpret_cast是一种程序员凌驾于c++的类型控制机制上的东西,超越它来做事,一切都控制在程序员手里

看例子:


class A{
int* pA;
public:
A()
{
pA = new int;
cout <<"A construct" <<endl;
}
virtual ~A()
{
cout <<"A descontruct" <<endl;
delete pA;
}
virtual void test()
{
cout <<"A test" <<endl;
}
};
class B
{
double* pB;
public:
B()
{
pB = new double;
cout <<"B construct" <<endl;
}
~B()
{
cout <<"B descontruct" <<endl;
delete pB;
}
void test()
{
cout <<"B test" <<endl;
}
};

int _tmain(int argc, _TCHAR* argv[])
{

B* b = reinterpret_cast<B*>(new A);
delete b;
}


这里照样会出错,归根结底,这是程序员的错而不是机制的错
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 hdt 的回复:]
try
[code=C/C++]class base{
public:
base()
{
cout < <"base construct" < <endl;
}
virtual ~base()
{
cout < <"base descontruct" < <endl;
}
virtual void test()
{
cout < <"base test" < <endl;
}
};
class Child:public base
{
int a;
public:
Child()
{
cout < <"child construct" < <…
[/Quote]

这个例子不足以推翻上面的说法

这里的array[i]访问,实际上是调用了operator[](),而该函数应该就是按照指针类型来寻址的,它自然会错。c++为我们保证的是对象的构造和析构尽量正确,但它并没有保证运算符[]也可以随便用的。

我们讨论的只是析构时的问题,当然虽然我觉得是可以用的,但是它的确不是那么好,这也是事实。
taodm 2008-03-18
  • 打赏
  • 举报
回复
《More Effective C++》item3 不要对数组使用多态.
不知道是不是和你们讨论相关。
Vitin 2008-03-18
  • 打赏
  • 举报
回复
在59楼所列出的三本书中,TC++PL已经于2000年出了(第三版的)特别版,与C++标准取得了同步。去年,Stroustrup写了一篇论文《Evolving a language in and for the real world: C++ 1991-2006》,描述了D&E之后的C++历史。至于ARM,我听说Stroustrup曾经计划与Andrew Koenig(the ANSI C++ committee's Project Editor,著名的Koenig Lookup的发明者)合写一本《The Annotated C++ Language Standard》,但似乎这本书一直也没有完成。所以,目前而言,ARM的RM部分可由《ISO/IEC 14882》来取代,但是其A部分(Annotated)仍然是不可取代的珍贵资源。
Vitin 2008-03-18
  • 打赏
  • 举报
回复
The Annotated C++ Reference Manual(简称ARM)是早期C++程序员必备的。在C++98国际标准出现之前,ARM就是事实上的C++标准。不过因为C++98增加了许多新的特性,也做了不少改动,现在ARM确实已经将权威性让位于C++的国际标准。

无论如何,ARM在C++的历史中发挥过重要的作用;在C++标准《ISO/IEC 14882:2003》中([intro.ack]),描述了它的历史地位:
The C + + programming language as described in this International Standard is based on the language as
described in Chapter R (Reference Manual) of Stroustrup: The C++ Programming Language (second edition,
Addison-Wesley Publishing Company, ISBN 0–201–53992–6, copyright  1991 AT&T).
此处的Chapter R 就是ARM的RM部分(the Reference Manual),它被作为附录加到了TC++PL(2nd)中。

并且迄今为止,ARM仍是一部不可多得的优秀参考书。因为,虽然现在它所展现的已经不再是完全标准的C++语言,但是它会使你有机会透彻地理解C++的各种特性。这样的机会并不多见,在我所知道的范围内,只有ARM、D&E(The Design and Evolution of C++)和TC++PL(The C++ Programming Language)做到了这一点(碰巧的是,它们都是Bjarne Stroustrup的书)。按照我的理解(以及Stroustrup在D&E中写到的),D&E阐述了C++的历史,ARM告诉你C++语言是什么,TC++PL则教会你如何使用它。现在来说,“语言是什么”由C++国际标准来回答,但是ARM可以帮助你更有效地理解C++国际标准。
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
我见都没见过,好奇问问 - -
taodm 2008-03-18
  • 打赏
  • 举报
回复
那个早过时了,直接扔了即可。
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
那个。。

The Annotated C++ Reference Manual 是90年写的?
Vitin 2008-03-18
  • 打赏
  • 举报
回复
[Quote=引用 54 楼 paidfighting 的回复:]
ISO/IEC 14882 776页,唉。。。
[/Quote]
巨大的挑战!
一般情况下,需要时查一下就可以了,呵呵。
paidfighting 2008-03-18
  • 打赏
  • 举报
回复
ISO/IEC 14882 776页,唉。。。
加载更多回复(41)

65,186

社区成员

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

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