请顶尖高手进来关注一下,为什么这个思路在Delphi下极易实现,在C++中却遇到这么大的困难。

wcmwcm 2004-05-06 02:00:53
这个帖子,别人提过,但结果并不理想,我在Delphi做过,C++却行不通。

下面代码不能编译通过,不过大体意图应该看得明白,请教:问题出在哪里?如何解决?
#include "stdio.h"

typedef void (*FUN)(void);

class CA
{
public:
FUN Fun;
void aaaa(void);
};

class CB
{
public:
void bbbb(void);
};

class CC
{
public:
void cccc(void);
};

void CA::aaaa(void)
{
if(Fun != 0)
Fun();
}

void CB::bbbb(void)
{
printf("bbbb");
}

void CC::cccc(void)
{
printf("cccc");
}

int main(void)
{
CA Aaa;
CB Bbb;
CC Ccc;

Aaa.Fun = Bbb.bbbb;
Aaa.aaaa();
Aaa.Fun = Ccc.cccc;
Aaa.aaaa();
return 0;
}

...全文
67 92 打赏 收藏 转发到动态 举报
写回复
用AI写文章
92 条回复
切换为时间正序
请发表友善的回复…
发表回复
Wolf0403 2004-05-06
  • 打赏
  • 举报
回复
楼上和我的原来的想法一样,不过我是觉得这样复杂所以就没用了,嘿嘿。
hyifeng 2004-05-06
  • 打赏
  • 举报
回复
好长的贴..


如果加入一个间接层可以避免多继承.
如:

struct handle {
virtual void invoke() = 0;
virtual ~handle() {}
};

template <class _Ty>
struct delegate : handle {
typedef void (_Ty::*pfun)();
typedef _Ty *pcls;

delegate(pfun the_fun, pcls the_cls)
: fun_(the_fun), cls_(the_cls)
{}

virtual void invoke() { (cls_->*fun_)(); }

private:

pfun fun_;
pcls cls_;
};

struct A {
void fa() {}
};

struct B {
viod fb() {}
};

int main(int, char *[]) {
A a;
B b;

handle* h1 = new delegate<A>(&A::fa, &a);
handle* h2 = new delegate<B>(&B::fb, &b);

h1->invoke(), h2->invoke();

delete h1;
delete h2;
}

大概这样,
没有运行过可能有错误.
complayer 2004-05-06
  • 打赏
  • 举报
回复
可以弄一个虚基类,这几个类都继承该类。代码如下:

#include "stdio.h"

class CA
{
public:
virtual void Fun(void) = 0;
};

class CB : public CA
{
public:
virtual void Fun(void);
};

class CC : public CA
{
public:
virtual void Fun(void);
};

void CB::Fun(void)
{
printf("bbbb\n");
}

void CC::Fun(void)
{
printf("cccc\n");
}

int main(void)
{
CA *Aaa;
CB Bbb;
CC Ccc;

// Aaa.Fun = Bbb.bbbb;
// Aaa.aaaa();
// Aaa.Fun = Ccc.cccc;
// Aaa.aaaa();

Aaa = &Bbb;
Aaa->Fun();
Aaa = &Ccc;
Aaa->Fun();
return 0;
}
Wolf0403 2004-05-06
  • 打赏
  • 举报
回复
wcmwcm(困惑在我心中)

你的类一定要派生自 TObject ?那么就是说,你是用的 BCB 了?看看 __closure 关键字吧,和 Delphi 的回调完全一样的。。。一个能力非常变态的扩展关键字
freefalcon 2004-05-06
  • 打赏
  • 举报
回复
呵呵,废人不必这么客气


[“回调类”或者“回调接口”这种方法将不得不用多继承。
我的类肯定要最终继承于TObject的,所以是多继承]

是的,要么用多继承,要么就用单继承先实现回调接口,然后再把这个类作为从TObject派生而来的类的成员(有点拗口)
Wolf0403 2004-05-06
  • 打赏
  • 举报
回复
哈哈,没开编译器偶就是在胡说八道。。。谢谢刀子
BluntBlade 2004-05-06
  • 打赏
  • 举报
回复
废人你的代码在DevC++下有问题!

Aaa.Fun = &(CB::Callback);
改成
Aaa.Fun = &(ICallback::Callback);
才行,否则编译器说类型不匹配。
而且此时Fun的值不是一个地址而是一个整数偏移量。
Wolf0403 2004-05-06
  • 打赏
  • 举报
回复
freefalcon(心宇):

抱歉,我直接看了标题就扯我的,没看前面的回复,嘿嘿。。。
wcmwcm 2004-05-06
  • 打赏
  • 举报
回复
我的类肯定要最终继承于TObject的,所以是多继承
Wolf0403 2004-05-06
  • 打赏
  • 举报
回复
那俺就继续。。。

class CA
{
public:
CallBackFunction Fun;
void aaaa(ICallback & callback_object){ callback_object.*Fun();}
};

int main(void)
{
CA Aaa;
CB Bbb;
CC Ccc;

Aaa.Fun = &(CB::Callback);// 好像是这个语法,记不清了
Aaa.aaaa(Bbb);
Aaa.Fun = &(CC::Callback);
Aaa.aaaa(Ccc);
return 0;
}

和 VCL 不同,C++ 中的方法是属于类的,所以必须通过 CB::Callback 这样的方法来取得函数地址。

回头看看 class CB 和 class CC ,我习惯叫他们 event source 了:)
Callback 是这些 event source 的公共接口。各个类实现自己的 Callback 方法代替原来的 bbbb cccc 方法。
这其实和 Java AWT 的 Event-Listener 机制有那么一点相似了吧。。。

设想一下,应该可以用一个模板类或者更好的方法来做更多的中间工作简化代码。。。就像是 .net 里面的 System.MulticastDelegate 一样。。。一个 Bridge 模式
BluntBlade 2004-05-06
  • 打赏
  • 举报
回复
多继承?没有啊?
是单根继承的嘛。
wcmwcm 2004-05-06
  • 打赏
  • 举报
回复
回调类”或者“回调接口”这种方法将不得不用多继承。
BluntBlade 2004-05-06
  • 打赏
  • 举报
回复
说白了不就是把函数指针藏在对象指针后面么……
freefalcon 2004-05-06
  • 打赏
  • 举报
回复
前面我也提到了,使用“回调类”或者说“回调接口”将很方便

示例


class ICallback
{
public:
virtual void foo(int some_value) = 0;
};

class A
{
public:
A(){};
void registerCallback(ICallback* pCallback)
{
m_pCallback = pCallback;
}

void test()
{
m_pCallback->foo(123);
}

private:
ICallback* m_pCallback;
};

class B : public ICallback
{
public:
B(){}

void foo(int some_value)
{
test = some_value;
}
private:
int test;
};

void main()
{
A aa;
B bb;
aa.registerCallback(&bb);
aa.test();
}
BluntBlade 2004-05-06
  • 打赏
  • 举报
回复
To 楼主

呃……你认为在现有的程序氛围中,有几个Delphi程序员有足够的耐心和时间去研究VCL的原理与实现?
wcmwcm 2004-05-06
  • 打赏
  • 举报
回复
BluntBlade(无锋之刃)(灌水是我无言的抗议):
仔细去看VCL做的做的非常棒,而且提供源码,并不使只是学会用的。
wcmwcm 2004-05-06
  • 打赏
  • 举报
回复
Wolf0403(完美废人)(灌水是我无言的抗议):
强烈要求继续,在这里我更想获得的是思路,并不是一个简单的解
BluntBlade 2004-05-06
  • 打赏
  • 举报
回复
用.net或者VCL只是学会用,要理解原理,看C++比较好。
wcmwcm 2004-05-06
  • 打赏
  • 举报
回复
BluntBlade(无锋之刃)(灌水是我无言的抗议):
非常感谢,多多支持
Wolf0403 2004-05-06
  • 打赏
  • 举报
回复
不知道一个 static member-function 和一个 global function 有什么区别。

delphi 的优势就是在于它的单根继承体系。所以 Anderson 去了 .net 就做了个 delegate,几乎还是一个原理。因为所有的对象都是派生自 object (TObject 或者 System.Object),所以可以用多态性质来用统一的接口操作任意的对象。C++ 中没有一个默认的“root”,所以各个独立类之间的联系就是很复杂的事情了。

按照楼主的意思,CB 和 CC 都有一个方法是作为 CA 的回调用,那么就是说,CB 和 CC 有公共的接口。根据重构之 Extract 法则(偶听说过的唯一重构法则^_^),将它提取成为 interface,得到:

class ICallback {virtual void Callback() = 0;};
typedef void (ICallback::*CallBackFunction)(void);

class CB : public ICallback
{public:
void Callback();
// ...
};

class CC : public ICallback
{public:
void Callback();
// ...
};

然后 CA 就可以变成

class CA
{
public:
CallBackFunction Fun;
void aaaa(void);
};

。。。还需要继续吗?
无论 .net 还是 VCL 都利用单根继承体系来极大地利用了多态的灵活性。C++ 中我们完全可以自己实现这样的优势。
谢谢^_^
加载更多回复(72)

64,684

社区成员

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

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