何谓数据结构
(网上说)数据结构是用来反映一个数据的内部构成,即一个数据由哪些成分数据构成,以什么方式构成。数据结构有逻辑上的数据结构和物理上的数据结构之分。逻辑上的数据结构反映成分数据之间的逻辑关系,而物理 上的数据结构反映成分数据在计算机内部的存储安排。数据结构是数据存在的形式。
数据结构是信息的一种组织方式,其目的是为了提高算法的效率,它通常与一组算法的集合相对应,通过这组算法集合可以对数据结构中的数据进行某种操作。
何谓对象模型
(本人说)对象模型是用来反映一个对象的数据结构,以及如何组织对此数据结构进行操作的函数集合,本人对这个函数集合的组织形式称之为函数结构。即对象模型包括数据结构和函数结构两部分。
对象模型的概念不管在《深度探索C++对象模型》,还是在《C++ Primer》中的描述都非常含糊。估计我的陈述在第一层面上很清晰,但是在第二层面——函数结构上还是很粗浅。
那么,下面仿照数据结构的方法,说明一下函数结构(有些说法叫做函数底层支持)。
首先,一般的函数调用
//
常规
class A
{
int foo( int x1, int x2)
{
return x1 + x2;
}
void main(void)
{
int y;
y=foo(1,2);
}
};
我们看看,绿色的部分的调用,这是最常用的方法,执行效率也最高,我们称之为
最简便。简便一词在本文占有非常重要的地位。
class A
{
int foo( int x1, int x2)
{
return x1 + x2;
}
void main(void)
{
int y;
y=foo(1,2);
}
};
我们把上面的类稍作改造:
//
函数指针
class A
{
int (*foo)( int x1, int x2);
int foo_impl( int x1, int x2)
{
return x1 + x2;
}
void main( void )
{
int y;
foo=foo_impl;
y=foo(1,2 );
}
};
class A
{
int (*foo)( int x1, int x2);
int foo_impl( int x1, int x2)
{
return x1 + x2;
}
void main( void )
{
int y;
foo=foo_impl;
y=foo(1,2 );
}
};
对比一下,调用起来没有什么两样,但是需要之前给函数指针赋值,效率上也有所减少,而且牺牲了this指针,不过也有办法可以让this指针找回来,不在本人论述范围。这种方法可以认为是 次简便。
我们再看看另外一种做法
//
函数指针数组
class A
{
int ( * foo)( int x1, int x2)[2];
int foo_impl( int x1, int x2)
{
return x1 + x2;
}
int foo_other_impl( int x1, int x2)
{
return (x1 + x2)*2;
}
void main( void )
{
int y;
foo[0]=foo_impl;
foo[1]=foo_other_impl;
y=(foo[0])(1,2 );
}
};
可以看到这种方法用起来实在不方便,函数指针数组也得依个赋值。这种方法可以认为是
很不简便。
class A
{
int ( * foo)( int x1, int x2)[2];
int foo_impl( int x1, int x2)
{
return x1 + x2;
}
int foo_other_impl( int x1, int x2)
{
return (x1 + x2)*2;
}
void main( void )
{
int y;
foo[0]=foo_impl;
foo[1]=foo_other_impl;
y=(foo[0])(1,2 );
}
};
还没完,再看看
//
带名字的函数指针数组
class A
{
struct {
char * name;
int ( * foo)( int x1, int x2);
}foos[ 100 ];
int invoke_foo( char * name, int x1, int x2)
{
for(int i=0;i<100;i++)
{
if(strcmp(foos[i].name,name)==0)
{
return (foos[i])(x1,x2);
}
}
}
int foo_impl( int x1, int x2)
{
return x1 + x2;
}
int foo_other_impl( int x1, int x2)
{
return (x1 + x2) * 2 ;
}
void main( void )
{
int y;
foos[ 0].name="foo1";
foos[0].foo=foo_impl;
foos[1].name="foo2";
foos[1]=foo_other_impl;
y=invoke_foo("foo1",1,2 );
}
};
可以看到这种方法用起来比上面纯粹函数指针数组来得方便一点点,但是功能缺很强大,这就是C++语言动态化的一种构想。这种方法可以认为是
不很简便。
class A
{
struct {
char * name;
int ( * foo)( int x1, int x2);
}foos[ 100 ];
int invoke_foo( char * name, int x1, int x2)
{
for(int i=0;i<100;i++)
{
if(strcmp(foos[i].name,name)==0)
{
return (foos[i])(x1,x2);
}
}
}
int foo_impl( int x1, int x2)
{
return x1 + x2;
}
int foo_other_impl( int x1, int x2)
{
return (x1 + x2) * 2 ;
}
void main( void )
{
int y;
foos[ 0].name="foo1";
foos[0].foo=foo_impl;
foos[1].name="foo2";
foos[1]=foo_other_impl;
y=invoke_foo("foo1",1,2 );
}
};
当然,把函数变成指针(虚函数在本文看来也是函数指针),是对象模型变得强大的一次飞跃。在函数变成指针后,再把指针通过数据结构进行组织,是把对象模型变得更强大的又一次飞跃。它就像数据结构中用指向数据结构的指针来组织数据比overlap跌跤来得更强大一样。
总的来说,对象模型的设计就是在方便性和功能可扩展性两方面取得平衡的艺术。