这里我要讨论的“虚”函数并不是指一般意义上的虚函数。因为虚函数能在不知其类型的情况下实现其多态特征。而这里所说的“虚”函数,只是一种compiler trick而以。
在一般面向对象语言中,如需要让父类调用派生类的函数,一般是通过多态来实现,也有如使用代理或者成员函数指针来实现。但是多态实现,不仅增加空间上的开销还增加时间上的开销。而使用代理虽然更加灵活,但是带来的开销和维护更大。但是并不是所有的父类调用子类函数都需要以这两种方式进行,例如DirectX SDK的CD3DApplication这一类情况,是可以在明确知道其子类型的情况下进行的子类成员函数调用,不知道是哪个天才想到使用模版来实现,我也是前段时间看WTL才发现这一神奇的魔术例如:
template<typename T>
class CBase
{
public:
void DoFoo()
{
(reinterpret_cast<T*>(this))->Foo();
}
void Foo()
{
}
};
class CDerive:public CBase<CDerive>
{
public:
void Foo()
{
cout<<"CDerive::Foo"<<endl;
}
};
这样带来的后果就是,基类成了无法实例化的了。但是却能方便调用派生类成员函数,再加上内联展开,能在一定程度上大大增加效率 而C#中实现这么一种方法,我给出的:
interface IFoo
{
void Foo();
}
class CBase<T> where T : IFoo
{
public void DoFoo()
{
T f = (T)(object)this;
f.Foo();
}
public void Foo()
{
}
}
class CDerive : CBase<CDerive>, IFoo
{
public new void Foo()
{
Console.WriteLine("CDerive::Foo");
}
}
但是这样的做法,就必须存在一个IFoo接口,来说明这个T有个Foo方法,为什么?因为C#2的泛型特化不是在编译期,而是在运行期由JIT实现的,编译器不可能知道这里的T会成为CDerive,所以T没有Foo方法是对的,就应该用接口来约束Foo方法了。
用接口来说明方法的存在带来的后果是,增加了空间的开销,因为这个CDerive必须维护一个有IFoo的接口表。而且通过反汇编分析,这样的做法减少了因为虚拟表的产生而导致的间接二次寻址,但是带来的问题是多了两次类型转换而产生的类型检查,这里却产生了效率开销,这个看起来比虚拟函数带来的执行开销更大
请问各位高手,觉得怎么样处理这个问题比较好?减轻VMT负担的同时增加执行效率。
这个问题只是在群里和别人聊天的时候想到的,呵呵,觉得好玩就发上来了,欢迎各位高手菜鸟拍砖
在一般面向对象语言中,如需要让父类调用派生类的函数,一般是通过多态来实现,也有如使用代理或者成员函数指针来实现。但是多态实现,不仅增加空间上的开销还增加时间上的开销。而使用代理虽然更加灵活,但是带来的开销和维护更大。但是并不是所有的父类调用子类函数都需要以这两种方式进行,例如DirectX SDK的CD3DApplication这一类情况,是可以在明确知道其子类型的情况下进行的子类成员函数调用,不知道是哪个天才想到使用模版来实现,我也是前段时间看WTL才发现这一神奇的魔术例如:
template<typename T>
class CBase
{
public:
void DoFoo()
{
(reinterpret_cast<T*>(this))->Foo();
}
void Foo()
{
}
};
class CDerive:public CBase<CDerive>
{
public:
void Foo()
{
cout<<"CDerive::Foo"<<endl;
}
};
这样带来的后果就是,基类成了无法实例化的了。但是却能方便调用派生类成员函数,再加上内联展开,能在一定程度上大大增加效率 而C#中实现这么一种方法,我给出的:
interface IFoo
{
void Foo();
}
class CBase<T> where T : IFoo
{
public void DoFoo()
{
T f = (T)(object)this;
f.Foo();
}
public void Foo()
{
}
}
class CDerive : CBase<CDerive>, IFoo
{
public new void Foo()
{
Console.WriteLine("CDerive::Foo");
}
}
但是这样的做法,就必须存在一个IFoo接口,来说明这个T有个Foo方法,为什么?因为C#2的泛型特化不是在编译期,而是在运行期由JIT实现的,编译器不可能知道这里的T会成为CDerive,所以T没有Foo方法是对的,就应该用接口来约束Foo方法了。
用接口来说明方法的存在带来的后果是,增加了空间的开销,因为这个CDerive必须维护一个有IFoo的接口表。而且通过反汇编分析,这样的做法减少了因为虚拟表的产生而导致的间接二次寻址,但是带来的问题是多了两次类型转换而产生的类型检查,这里却产生了效率开销,这个看起来比虚拟函数带来的执行开销更大
请问各位高手,觉得怎么样处理这个问题比较好?减轻VMT负担的同时增加执行效率。
这个问题只是在群里和别人聊天的时候想到的,呵呵,觉得好玩就发上来了,欢迎各位高手菜鸟拍砖
解决方案 »
- 每次重启电脑Cookies就消失了,怎么回事?
- 把数字保存成excel文件
- 在IE中欠入浏览WORD文档,如何控制在显示的Word文档中不能操作任何Ctrl+c,Ctrl+v等键盘操作。
- datatable数据筛选问题,高手指点一下
- 关于密码加密后在网络上流通的问题,钻个牛角尖,请高手帮忙解惑,谢谢!
- 菜鸟求救!如何使用Random类写一个随机生成制定范围内的数?
- 关闭窗体时报错:未处理AccessViolationException--尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
- .net 如何查询List<string>中某个出现次数大于2次的元素
- 如果是做数据库方面的项目,C#的效果如何?
- c#+SQLSERVER中的数据库登录
- 怎样用代码激活一个事件?
- SQL问题
已阅!这个问题的确存在,所以说C#是强类型,是安全代码(语言)我没有好的方法处理. up
http://blog.joycode.com/sunmast/archive/2005/12/16/csharp_generic_misleading.aspx事实上C# 2.0中的泛型限制较多,微软提供的解决方案也不尽如人意,有很多问题都没有得到解决,但不可否认能使其处于一种相对平衡的状态也不失为一件好事。我个人觉得那些所谓的方案基本上都是一样的,没有哪个能真正把所有问题都解决的,所以关键依然是看在实际开发的过程中开发人员如何去取舍。基本上就是这样了^_^
用接口来说明方法的存在带来的后果是,增加了空间的开销,因为这个CDerive必须维护一个有IFoo的接口表。而且通过反汇编分析,这样的做法减少了因为虚拟表的产生而导致的间接二次寻址,但是带来的问题是多了两次类型转换而产生的类型检查,这里却产生了效率开销,这个看起来比虚拟函数带来的执行开销更大"必须去花时间去考虑接口对系统造成的影响吗?
相比起来我到是必须得花大时间琢磨目前项目中那个该死的资产编码规则,我看还是忘了他吧
呵呵
@.@||~
我的代码中效率瓶颈在两次类型转换。
按照不同的需求,我可以选择C/C++,Delphi甚至汇编。并不是天下只有C#的前面说的我这里的接口调用并没有产生接口带来的虚函数调用开销,是通过理论和反汇编得到的不过和一般的继承并覆盖父类虚函数相比,限制多了,多态式虚函数允许public/protected,而这种方式只能public,呵呵
{
void Foo();
} public class VFBase : IFoo
{
public void DoFoo()
{
(this as IFoo).Foo();
} public void Foo()
{
}
} public class VFDerive : VFBase, IFoo
{
public new void Foo()
{
Console.WriteLine("VFDerive::Foo");
}
}前面有人贴出了我的那个blog链接,那个不说明这个问题嗯.. 而且其内容备受争议,仅供参考:-)
而且前面说过我纯属无聊的讨论:)
C#或托管代码泛型必须基类+接口,没办法,这是规矩,C#泛型约束更多还有各位前辈,托管代码强调的都是"显示....."
咋不见你们用Generic呢,看的人迷茫啊 ~~~~
:)