[UE C++] Использование интерфейса

[UE C++] Использование интерфейса

1. Концепция

Классы интерфейса помогают гарантировать, что набор общих функций реализуется группой (потенциально) несвязанных классов, которые не имеют общего родительского класса, но требуют одинаковой функциональности. В этом случае рекомендуются интерфейсы.

В собственном C++ нет интерфейса, поэтому разработчики C++ вместо интерфейсов используют чисто абстрактные классы. В UE, чтобы обеспечить возможность включения интерфейса в систему отражения для управления, введен UInterface. UInterface наследует от UObject, но когда разработчикам UE необходимо использовать интерфейсы, если они напрямую наследуют от UInterface, возникнут проблемы с алмазным наследованием . Хотя эту проблему можно облегчить с помощью виртуального наследования, это небезопасно. Поэтому, когда мы создаем интерфейс, будет два класса. Второй класс - это то, где разработчики определяют функции интерфейса. Он не наследуется ни от одного класса, что позволяет избежать ромбовидного наследования. Первый класс наследуется от UInterface, главным образом для того, чтобы позволить классу интерфейса быть включенным в систему отражения UE.

2. Создать интерфейс

Новый класс C++ Прокрутите вниз и выберите Unreal Interface. Не нажимайте «Показать все классы», чтобы выбрать. Его невозможно найти.

3. Объявить функции интерфейса

3.1 Определено в C++

UFUNCTION()
virtual void UFUNCTIONTesFun(float value) {};//UFunction虚函数

virtual void VirtualTestFun(float value) {};//普通虚函数,须有定义

virtual void PureVirtualTestFun(float value) = 0;//纯虚函数

Меры предосторожности:

  • Функция интерфейса должна быть объявлена ​​как виртуальная функция, чтобы иметь смысл. Если ключевое слово virtual не добавлено, компиляция может не пройти (есть знак UFUNCTION). Если она пройдет, это будет переопределение функции, а не перегрузка функции.
  • Объявленные виртуальные функции Not Pure должны иметь соответствующие определения в интерфейсе. «{}» в приведенном выше примере использует пустое определение, чтобы предотвратить сбой компиляции.
  • Если в интерфейсе существует виртуальная функция Pure, класс, наследующий этот интерфейс в C++, должен реализовать эту функцию, иначе компиляция не пройдет. Классы Blueprint, реализующие этот интерфейс, не оказывают никакого эффекта.

3.2 Определить в чертеже

UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
void BlueprintImpTestFun(float value);//不能有virtual

UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void BlueprintNatTesFun(float value);//不能有virtual
virtual void BlueprintNatTesFun_Implementation(float value) {};//可以不在接口类中声明定义。只在实现自该接口的C++类中声明并定义

Меры предосторожности:

  • BlueprintCallableФункции, помеченные как вызываемые по схеме, также должны существовать BlueprintImplementableEventили BlueprintNativeEventбыть помечены. Объявленная при этом функция не может быть виртуальной функцией (в Blueprint предусмотрены специальные методы обработки виртуальных функций)
  • Если вы хотите, чтобы класс интерфейса был реализован только на C++, Blueprint не сможет его реализовать. Класс интерфейса можно пометить как UINTERFACE(meta = (CannotImplementInterfaceInBlueprint)), но нельзя добавить BlueprintImplementableEventили BlueprintNativeEventотметить, иначе компиляция не пройдет. В настоящее время она существует одна BlueprintCallable, что указывает на то, что эта функция может быть вызвана из проекта.

4. Реализуйте и используйте классы интерфейса.

Вот мой класс интерфейса

UINTERFACE(MinimalAPI)
class UInterfaceTest : public UInterface
{
	GENERATED_BODY()
};

class STUDY427TEST_API IInterfaceTest
{
	GENERATED_BODY()

public:

	UFUNCTION(BlueprintCallable, BlueprintImplementableEvent)
	void BlueprintImpTestFun(float value);

	UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
	void BlueprintNatTesFun(float value);
	virtual void BlueprintNatTesFun_Implementation(float value) {};

	UFUNCTION()
	virtual void UFUNCTIONTesFun(float value) {};

	void NormalFun(float value);//此函数无作用,用于测试蓝图覆盖
	
	virtual void VirtualTestFun(float value) {};

	virtual void PureVirtualTestFun(float value) = 0;
};

4.1 Реализация класса интерфейса

То, что было упомянуто выше, IInterfaceTest— это то, где разработчики объявляют интерфейсные функции, поэтому им нужно их наследовать; UInterfaceTestэто вспомогательный класс, используемый для отражения.

class STUDY427TEST_API AInterfaceTestActor : public AActor, public IInterfaceTest

4.2 Определите, реализован ли класс интерфейса

4.2.1 Через класс

Здесь используется UInterfaceTestотражение, чтобы судить

bool bIsImplemented = false;

bIsImplemented = this->GetClass()->ImplementsInterface(UInterfaceTest::StaticClass());

bIsImplemented = this->Implements<UInterfaceTest>();

Implements<UInterfaceTest>()GetClass()->ImplementsInterface(UInterfaceTest::StaticClass())Метод фактически вызывается внутри

4.2.2 Сквозная трансляция

Используется то IInterfaceTest, что класс C++ наследует от него IInterfaceTest, поэтому объект Cast является им.

IInterfaceTest* MyInterfaceTest = Cast<IInterfaceTest>(this);
if(MyInterfaceTest)
{
    //内部逻辑
}

Примечание. Этот метод не может определить , реализует ли класс схемы интерфейс, поскольку класс схемы использует интерфейс не через наследование, поэтому Cast недействителен . Метод оценки с использованием класса (4.2.1)

4.3 Вызов функций интерфейса

4.3.1 Функции, определенные в C++

Просто используйте обычные методы вызова функций C++.

IInterfaceTest* MyInterfaceTest = Cast<IInterfaceTest>(TestActor);
if (MyInterfaceTest)
{
    MyInterfaceTest->UFUNCTIONTesFun(10.f);
    MyInterfaceTest->PureVirtualTestFun(20.0f);
    MyInterfaceTest->VirtualTestFun(30.0f);
}
4.3.2 Функции, определенные в чертежах

Если вы по-прежнему используете IInterfaceTest::Execute_XXXXX(Actor, Parameter···)описанный выше метод для принудительного вызова, редактор может выйти из строя.

//使用之前判断是否实现该接口更保险
IInterfaceTest::Execute_BlueprintImpTestFun(this,50.0f);
IInterfaceTest::Execute_BlueprintNatTesFun(this, 60.0f);

Справочная ссылка

Supongo que te gusta

Origin blog.csdn.net/qq_52179126/article/details/129979662
Recomendado
Clasificación