5

类 A 有一个类 B 的实例作为成员。有时 B 类的实例想与 A 类对话。在 Objective-C 中我可以这样做:

// A.h
@interface A : NSObject <BDelegate>
@property (nonatomic, retain) B *b;
@end 

// A.m
- (void) classBsays {

}


// B.h
@protocol BDelegate
- (void) classBsays;
@end

@interface B : NSObject
@property (nonatomic, assign) id<BDelegate> delegate;
@end

// B.m
@implementation B
- (void) f {
    [delegate classBsays];
}
@end

我在 C++ 中使用 B 类上的 void 指针做了类似的事情。但这错过了“B 类的委托应该实现这样那样的方法”的部分。

如何在 C++ 中模仿 Objective-C 的协议?

4

2 回答 2

5

您的示例的 C++ 等效项如下所示:

// A.hpp
#include "B.hpp"

class A : public BDelegate {
    public:
        void classBSays ( ) { }
        B* b;
};

// B.hpp
class BDelegate {
    public:
        virtual void classBSays( ) = 0;
};
class B {
    public:
        void f ( ) { delegate->classBSays( ); }
        BDelegate* delegate;
};

请注意,为了简洁起见,我在这里使用了成员函数的内联实现 - 如果需要,您可以同样在单独的文件中实现A.classBSays()和。B.f()A.cppB.cpp

在此示例中,该类BDelegate是一个抽象基类 (ABC),相当于您的BDelegate协议。通过只包含纯虚成员函数(以关键字virtual=0后缀开头的函数),它强制其子类为这些方法提供实现,就像@required在 Objective-C 协议中使用标签(或无标签)所做的那样。BDelegate仅包含此类功能的事实使其成为 ABC。

您可以通过在 ABC 中为函数指定一个空主体来模拟 Objective-C@optional标记,这意味着不需要子类来实现它(因为它是在 ABC 中实现的)。例如,您可以通过如下foo修改来模拟可选方法:BDelegate

@protocol BDelegate
- (void) classBsays;
@optional
- (void) foo;
@end
// Is approximately equivalent to:
class BDelegate {
    public:
        virtual void classBSays( ) = 0;
        virtual void foo( ) { }
};

使用该定义,类A可以根据需要选择是否提供定义foo。但是请注意,这并不完全等同于 Objective-C@optional表示法,因为如果它不提供自己的覆盖,它A仍然会继承BDelegate'方法。foo另一方面,Objective-C 协议A根本没有这样的方法,除非它自己显式地实现它。

可在此处获得对该主题的更全面介绍。

于 2013-09-11T22:58:44.813 回答
2

您可以通过定义抽象基类在 C++ 中实现基本相同的功能。也就是说,您只定义方法签名而不提供任何实现。这需要任何子类来实现声明的方法。

这是您翻译成 C++ 的示例:

// A.h
class A : public BDelegate {
    B *b;
};

// A.m
Result A::classBsays {

}

// B.h
class BDelegate {
    virtual Result classBsays() = 0;
};

class B {
    BDelegate* delegate;
};

// B.m
void B::f {
    delegate->classBsays();
}

请注意,这可能无法编译,因为它缺少一些重要的东西。您将需要一个构造函数,传入 B 引用,甚至可能使用 astd::shared_ptr作为委托,等等。但是一般的形状是这样的。

重要的部分是方法声明BDelegate::classBsays()= 0方法签名之后,并且没有实现主体。这意味着该方法是纯虚拟的,这意味着子类必须实现该方法,否则无法实例化。(这是有道理的,否则您可能会调用一个没有实现的方法!)任何具有一个或多个纯虚拟方法的类本身就是一个纯虚拟类。正如您所描述的,这非常常用来定义解耦系统不同部分的接口。

于 2013-09-11T22:57:59.670 回答