Objective-C @protocol эквивалент в переполнении стека

Класс 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 ++, используя указатель void на класс B. Но здесь пропущена часть, в которой говорится, что «делегат класса B должен реализовывать такие-то и такие-то методы».

Как я могу имитировать протокол Objective-C в C ++?

3

Решение

Эквивалент 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.cpp а также B.cpp файлы, если вы хотели.

В этом примере класс BDelegate абстрактный базовый класс (ABC), эквивалентный вашему BDelegate протокол. Содержит только чисто виртуальные функции-члены (функции с предшествующим ключевым словом virtual и с =0 суффикс), он заставляет свои подклассы предоставлять реализации для этих методов, подобно использованию @required тег (или без тега) делает в протоколе Objective-C. Дело в том, что BDelegate содержит только такие функции, что делает его азбукой.

Вы можете подражать Objective-C @optional пометить, указав пустое тело для функции в вашем ABC, что означает, что подклассы не требуются для его реализации (так как это реализовано в 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«s foo метод, если он не обеспечивает свое собственное переопределение. С протоколом Objective-C, с другой стороны, A не будет иметь такой метод вообще, если он явно не реализует его сам.

Более подробное введение в предмет доступно Вот.

4

Другие решения

Вы можете достичь в основном того же в 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, возможно, даже используйте std::shared_ptr для делегата и так далее. Но общая форма примерно такая.

Важной частью является объявление метода для BDelegate::classBsays() имеет = 0 после подписи метода, и не имеет тела реализации. Это означает, что метод чисто виртуальный, что означает подкласс должен реализовать метод, или его нельзя реализовать. (Это имеет смысл, в противном случае вы могли бы потенциально вызвать метод, который не имеет реализации!). Любой класс, имеющий один или несколько чистых виртуальных методов, сам является чистым виртуальным классом. Это очень часто используется так же, как вы описываете, чтобы определить интерфейсы, которые разъединяют различные части системы.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector