Проверку поддержки интерфейса можно производить, выполняя динамическое приведение типа указателя и обрабатывая исключение, которое может при этом возникнуть. Однако более изящным решением будет выполнять проверку до приведения типа, избегая при этом возникновения исключений. Если объект поддерживает необходимый интерфейс, можно выполнять приведение типа для получения доступа к интерфейсу. С# поддерживает использование удобного оператора is для проверки того, поддерживает ли объект определенный интерфейс. К сожалению, в C++ с этой целью приходится использовать метод отражения, реализуемый посредством методов GetType и Getlnterf асе. В связи с тем, что это приводит к появлению несколько громоздкого выражения, в следующем примере с помощью директивы #define определяется макрос IS (THIS, THAT_INTERFACE), используемый далее в двух условных операторах if.
//TestlnterfaceBeforeCast.срр
//MACRO: pObj->GetType()->GetInterface("Somelnterface")!=0
// МАКРОС
#define IS(THIS, THAT_INTERFACE) (THIS->GetType()->GetInterface(
THAT_INTERFACE)!=0)
#using <mscorlib.dll>
using namespace System;
// использование пространства имен Система;
_gc _interface ICustomer1 {};
// сборщик мусора - ICustomer1;
_gc _interface ICustomer2 : ICustomer1
// сборщик мусора - ICustomer2: ICustomer1
{
public:
void ShowCustomers(int id); // идентификатор
};
_gc class Customer! : public ICustomer1 {};
// класс сборщика мусора Customerl: ICustomerl {};
_gc class Customer2 : public ICustomer2
// класс сборщика мусора Customer2: ICustomer2
{
public:
void ShowCustomers(int id) // идентификатор
{
Console::WriteLine("Customer2::ShowCustomers:
succeeded");
}
};
void main(void) // главный
{
Customerl *pCustl = new Customerl; // не к ICustomer2
Console::WriteLine(pCustl->GetType());
// проверить, относится ли к типу ICustomer2 перед приведением
if (IS(pCustl, "ICustomer2"))
{
ICustomer2 *plcust2 =
dynamic_cast<ICustomer2 *>(pCustl);
plcust2->ShowCustomers(-1);
}
else
Console::WriteLine
("pCustl does not support ICustomer2 interface");
// ("pCustl не поддерживает интерфейс ICustomer2");
Customer2 *pCust2 = new Customer2; // да, на ICustomer2
Console::WriteLine(pCust2->GetType());
// проверить, относится ли к типу ICustomer2 перед приведением
if (IS(pCust2, "ICustomer2"))
{
ICustomer2 *plcust2 =
dynamic_cast<ICustomer2 *>(pCust2);
pIcust2->ShowCustomers(-1);
}
else
Console::WriteLine
("pCust2 does not support ICustomer2 interface");
// ("pCust2 не поддерживает интерфейс ICustomer2");
}
В этом примере продемонстрировано далеко не оптимальное решение, так как проверка типа производится дважды. Первый раз — при использовании отражения для проверки поддержки интерфейса в макросе IS. А еще раз проверка производится автоматически — при выполнении динамического приведения типа, в этом случае, если интерфейс не поддерживается, возникает исключение. Результат работы программы приведен ниже. Обратите внимание, что при выполнении программы действительно не возникает исключения.
Customer1
pCustl does not support ICustomer2 interface
Customer2
Customer2::ShowCustomers: succeeded
А вот и перевод:
Customer1
pCustl не поддерживает интерфейс ICustomer2
Customer2
Customer2:: ShowCustomers: успешно