1

在以下极其缩写的类中,我想在基类中定义一个方法(ProcessLines),该方法将遍历一组数据库记录,将每条记录作为参数传递给仅在子类中定义的函数。显然 Base 是一个永远不会自行实例化的虚拟类。

Class Base {
 public:
  typedef ProcLineFunc( Long *Line );
  void ProcessLines( ProcLineFunc pf);
}

Class Child{
  void DoWork( Long *Line) { //do something}
}

我不确定如何实现这一点。如果我在子项中重新声明 ProcessLines 并仅调用父方法,则会收到与在创建子项的代码中调用 ProcessLines 相同的错误消息。

Child c(//something);
c.ProcessLines(c.DoWork);

给我一个编译器消息:

[BCC32 错误] main.cpp(67): E2034 无法转换 'bool (* (_closure )(long *))(long )' >to 'int ( )(long *)'
完整的解析器上下文
main.cpp(56) : class Add2Chan
main.cpp(78): 决定实例化: bool Add2Chan::ProcessByLines()
--- 重置解析器上下文以进行实例化...
main.cpp(67): 解析: bool Add2Chan::ProcessByLines()

我对 c++ 还很陌生,E2034 错误消息吓到我了。

请帮忙。我使用了 typedef,这样我就可以在我的子类中多次调用 ProcessLines,并在执行过程中传递不同的函数。

4

3 回答 3

4

通常你会用一个受保护的纯虚函数来做这种事情:

class Base {
  public:
    ProcessLines() {
        //Logic to process lines here, obviously psuedo-code
        while(moreLines) {
            ProcessLine(line);
        }
    }
  protected:
    virtual void ProcessLine(const Line& line) = 0;
}

class Child : public Base {
  protected:
    void ProcessLine(const Line& line) { //Logic to process the line for this type }
};

class DifferentChild : public Base {
  protected:
    void ProcessLine(const Line& line) { //Logic to process the line for DifferentChild }
};

我想这就是你要找的东西。在我看来,您正试图以一种奇怪的方式实现多态性,但这是在 C++ 中实现它的正常方式。

于 2012-06-10T20:09:14.707 回答
1

不要使用指向函数的指针,而是使用指向对象的指针。接受你的函数将被调用的限制,DoWork没有别的,每个类中只能有一个这样的函数。这不是一个糟糕的限制。在类(称为接口)中声明(纯虚)函数,并从中派生类(称为实现接口)。

struct DoingWork
{
    virtual void DoWork(long *Line) = 0; // does some work on a list
};

struct DoingGreatWork: DoingWork
{
    virtual void DoWork(long *Line) {printf("Great work\n");}
};

struct DoingSlightWork: DoingWork
{
    virtual void DoWork(long *Line) {printf("Slight work\n");}
};

使用这个例子:

class Base {
  public:
    void ProcessLines(DoingWork& object) {
        //Logic to process lines here
        while(moreLines) {
            object.DoWork(line);
        }
    }
};

class Whatever // no need to derive from Base
{
    void DoStuff()
    {
        Base object;

        object.ProcessLines(DoingGreatWork());
        object.ProcessLines(DoingSlightWork());
    }
}

如果工作对象必须有权访问调用对象,请像这样初始化它们:

class Whatever // no need to derive from Base
{
    struct DoingElaborateWork: DoingWork
    {
        Whatever& caller;
        DoingElaborateWork(Whatever& caller): caller(caller) {}
        virtual void DoWork(long *Line)
        {
            printf("Doing work requested by %s\n", caller.name());
        }
    };

    void DoStuff()
    {
        Base object;
        object.ProcessLines(DoingElaborateWork(*this));
    }

    const char* name() {return "Whatever";}
}

PS 他们说“在 C++03 中,函数是二等公民”,因为你不能用函数做你可以用对象做的事情(比如我提供的这个解决方案)。我听说在 C++11 中函数有了很大改进,但我不确定细节。

于 2012-06-10T22:13:19.977 回答
0

由于您在 C++Builder 中执行此操作,因此您可以利用它的__closure扩展来完全按照您的要求进行操作(VCL 的某些部分正是为自己的回调执行此操作):

class Base
{ 
public: 
    virtual ~Base() {}

    typedef void (__closure *ProcLineFunc)( Long *Line ); 
    void ProcessLines( ProcLineFunc pf); 
}; 

class Child : public Base
{ 
public:
    void DoWork( Long *Line) { //do something} 
}; 

Child c(...); 
c.ProcessLines(c.DoWork); 
于 2012-06-27T00:40:07.763 回答