当多态遇上数组 ... [C++, C++/CLI, C#]

本文主要探讨在C++、C++/CLI和C#中多态与数组的相关问题。在C++里,数组存放物长度不一致会引发程序问题,建议用STL容器类协助实现多态;还介绍了C++/CLI托管类型中用数组实现多态的情形,以及C#中数组实现多态的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当多态遇上数组 ... [C++, C++/CLI, C#]

When Polymorphism Meets Arrays ... [C++, C++/CLI, C#]

Written by Allen Lee

犹如星空与海鸥,漫画里根本你我一生永不会聚头,但我誓要共你牵手。

—— 古巨基,《美雪,美雪》

1. 能力测试

请回答下面的问题:

实现多态的效果,我们需要具备哪些条件?

上面的题目仅用于测试你是否具备阅读本文的必要条件。如果你对此题毫无头绪,那么我建议你尽快交叉本文。当然,要顺畅阅读本文,你还需要具备一些C++、C++/CLI和C#的基础知识。我想不必特别声明,建议当然是主观的。不过我愿意再说一次:建议是主观的,你有选择。

2. ... In C++,

好吧,既然你走到这一步,我建议你坚持下去。当然,你还是随时可以交叉本文,总之,你有选择。来,请先看看如下代码:

None.gif //Code#01
None.gif

None.gif#include<tchar.h><br><img src="/Images/OutliningIndicators/None.gif" align="top"><span style="COLOR: #0000ff">#include</span><iostream><br><img src="/Images/OutliningIndicators/None.gif" align="top"><br><img src="/Images/OutliningIndicators/None.gif" align="top"></iostream></tchar.h>
class A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifstd::coutExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}
;
None.gif
None.gif
class B: public A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()override
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifstd::coutExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}
;
None.gif
None.gif
class C: public A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()override
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifstd::coutExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}
;
None.gif
None.gif
void Print(Aarr[], int count)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifarr[i].Print();
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif
None.gif
int _tmain( int argc,_TCHAR*argv[])
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
constintCOUNT=11;
InBlock.gif
InBlock.gifAa_arr[COUNT];
InBlock.gifPrint(a_arr,COUNT);
InBlock.gif
InBlock.gifBb_arr[COUNT];
InBlock.gifPrint(b_arr,COUNT);
InBlock.gif
InBlock.gifCc_arr[COUNT];
InBlock.gifPrint(c_arr,COUNT);
InBlock.gif
InBlock.gif
return0;
ExpandedBlockEnd.gif}

  • A:请告诉我,Code #01有没有问题?
  • B:Easy job!把它编译并运行一下就知道了呗!

接着,阿B编译了这段代码,程序运行后,阿B发现输出结果正是我们所期望的。于是,阿B得出结论:这段代码没问题!

然而,你是否知道这段代码其实隐藏着一个计时,只要时机一到,它就会引爆并使你的程序完全瘫痪?不信?那我只好让你见识一下这个引爆是的情景了。现在,我分别为class B和class C加入一个field,并修改一下main()以便给class B和class C里的field赋值(注意,本赋值操作不是必须的!):

None.gif //Code#02
None.gif

None.gif#include<tchar.h><br><img src="/Images/OutliningIndicators/None.gif" align="top"><span style="COLOR: #0000ff">#include</span><iostream><br><img src="/Images/OutliningIndicators/None.gif" align="top"><br><img src="/Images/OutliningIndicators/None.gif" align="top"></iostream></tchar.h>
class A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifstd::coutExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}
;
None.gif
None.gif
class B: public A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()override
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifstd::coutExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gif
longL;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
class C: public A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()override
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifstd::coutExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gif
doubleD;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
void Print(Aarr[], int count)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifarr[i].Print();
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif
None.gif
int _tmain( int argc,_TCHAR*argv[])
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
constintCOUNT=11;
InBlock.gif
InBlock.gifAa_arr[COUNT];
InBlock.gifPrint(a_arr,COUNT);
InBlock.gif
InBlock.gifBb_arr[COUNT];
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifb_arr[i].L=141214121412;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(b_arr,COUNT);
InBlock.gif
InBlock.gifCc_arr[COUNT];
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifc_arr[i].D=3.141592654;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(c_arr,COUNT);
InBlock.gif
InBlock.gif
return0;
ExpandedBlockEnd.gif}

计时终于被引爆了:

o_01.JPG

可见程序无法找到b_arr[1]确切位置,其后果不会好过你在街上把一个背影看似相熟的女性误认为是你的女朋友时所产生的尴尬。至于产生这个问题的原因,Scott Meyers已经在他的《More Effective C++》作了详细的讲解[1],这里我就没必要重复劳动了。

显然,产生这个问题的根本原因是数组里的存放物长度不一致,如果能够让存放物的长度统一起来,问题就会迎刃而解了。问题男提出把指针放进数组,好吧,现在我们来看一下C++中多态与数组牵手的景象:

None.gif //Code#02'
None.gif//SeeCode#02forClassA,ClassBandClassC.
None.gif

None.gif
void Print(A*arr[], int count)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifarr[i]->Print();
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif
None.gif
int _tmain( int argc,_TCHAR*argv[])
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
constintCOUNT=11;
InBlock.gif
InBlock.gifA**a_arr=
newA*[COUNT];
InBlock.gifB**b_arr=
newB*[COUNT];
InBlock.gifC**c_arr=
newC*[COUNT];
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifa_arr[i]=
newA;
InBlock.gifb_arr[i]=
newB;
InBlock.gifb_arr[i]->L=141214121412;
InBlock.gifc_arr[i]=
newC;
InBlock.gifc_arr[i]->D=3.141592654;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(a_arr,COUNT);
InBlock.gifPrint(reinterpret_cast(b_arr),COUNT);
InBlock.gifPrint(reinterpret_cast(c_arr),COUNT);
InBlock.gif
InBlock.gif
return0;
ExpandedBlockEnd.gif}

问题解决了,不过,我还是强烈建议你(当然,你有选择!):

在C++中,请尽量使用STL中的容器类来协助实现多态的效果。

3. ... In C++/CLI,

在C++/CLI的托管类型(Managed Type)中,只有ref class(或ref struct[2]可用于建立继承体系。下面,我们来看看在C++/CLI中使用数组实现多态的情形:

None.gif //Code#03
None.gif

None.gif
using namespace System;
None.gif
using namespace stdcli::language;
None.gif
None.gif
ref class A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifConsole::WriteLine("A");
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}
;
None.gif
None.gif
ref class B: public A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()override
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifConsole::WriteLine("B");
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gif
longL;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
ref class C: public A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
public:
InBlock.gif
virtualvoidPrint()override
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifConsole::WriteLine("C");
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gif
doubleD;
ExpandedBlockEnd.gif}
;
None.gif
None.gif
void Print(array^arr)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
for(inti=0;iCount;++i)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifarr[i]->Print();
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif
None.gif
int _tmain()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
constintCOUNT=11;
InBlock.gif
InBlock.gifarray^a_arr=gcnewarray(COUNT);
InBlock.gif
for(inti=0;iCount;++i)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifa_arr[i]=gcnewA;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(a_arr);
InBlock.gif
InBlock.gifarray^b_arr=gcnewarray(COUNT);
InBlock.gif
for(inti=0;iCount;++i)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifb_arr[i]=gcnewB;
InBlock.gifb_arr[i]->l=141214121412;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(b_arr);
InBlock.gif
InBlock.gifarray^c_arr=gcnewarray(COUNT);
InBlock.gif
for(inti=0;iCount;++i)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifc_arr[i]=gcnewC;
InBlock.gifc_arr[i]->d=3.141592654;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(c_arr);
ExpandedBlockEnd.gif}

4. ... In C#,

而在C#中,使用数组来实现多态又是如何的呢:

None.gif //Code#04
None.gif

None.gif
using System;
None.gif
None.gif
class A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
publicvirtualvoidPrint()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifConsole.WriteLine("A");
ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

None.gif
None.gif
class B:A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
publicoverridevoidPrint()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifConsole.WriteLine("B");
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gif
publiclongL;
ExpandedBlockEnd.gif}

None.gif
None.gif
class C:A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
publicoverridevoidPrint()
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gifConsole.WriteLine("C");
ExpandedSubBlockEnd.gif}

InBlock.gif
InBlock.gif
publicdoubleD;
ExpandedBlockEnd.gif}

None.gif
None.gif
class Program
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif
staticvoidMain(string[]args)
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif{
InBlock.gif
constintCOUNT=11;
InBlock.gif
InBlock.gifA[]a_arr=
newA[COUNT];
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifa_arr[i]=
newA();
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(a_arr);
InBlock.gif
InBlock.gifB[]b_arr=
newB[COUNT];
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{
InBlock.gifb_arr[i]=
newB();
InBlock.gifb_arr[i].L=141214121412;
ExpandedSubBlockEnd.gif}

InBlock.gifPrint(b_arr);
InBlock.gif
InBlock.gifC[]c_arr=
newC[COUNT];
InBlock.gif
for(inti=0;iExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值