2013-09-11 2 views
3

Класс A имеет экземпляр класса B в качестве члена. Иногда экземпляр класса B хочет поговорить с класса А. В Objective-C я могу сделать:Objective-C @protocol эквивалент в 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 должен внедрять такие и такие методы».

Как я могу подражать протоколу Objective-C на C++?

+2

Класс C++ с только чистыми виртуальными функциями-членами (см. [This] (http://stackoverflow.com/questions/318064) для базового ввода) примерно эквивалентен протоколу Objective-C. – Mac

ответ

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 содержит только такие функции, является тем, что делает его ABC.

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

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

1

Вы можете достичь в основном того же языка в 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

протокол также может определять необязательные методы, которые будут удовлетворяться виртуальными методами с реализацией {}, а не объявляться как чистый виртуальный – Petesh

+1

@Petesh: это, вероятно, самый близкий эквивалент, но не совсем то же самое. В частности, если класс C++ 'BDelegate' содержал функцию' virtual foo() {} ', вы можете быть уверены, что' A' имеет такую ​​функцию-член. С другой стороны, если протокол Objective-C 'BDelegate' содержит' @optional - (void) foo; ', то' A' может иметь или не иметь метод 'foo' (в зависимости от того, явно ли он реализован в 'A' или нет). – Mac

+0

... и вызывающий может определить факт, что необязательный метод реализован или нет, и соответственно изменить его поведение таким образом, который не может быть достигнут реализацией по умолчанию в некотором базовом классе. – gnasher729

Смежные вопросы