Architecture Net или что такое Microsoft.NET?




Программирование с использованием интерфейсов

Использование интерфейсов облегчает программирование на управляемом C++. Интерфейсы реализуются через классы, и для получения указателя на интерфейс можно выполнить приведение указателя на класс. Методы интерфейсов можно вызывать, используя и указатели на класс, и указатели на интерфейс; однако для того, чтобы полностью воспользоваться достоинствами полиморфизма, предпочтительно везде, где только возможно, использовать указатели на интерфейсы.

Реализация интерфейсов

В C++ указание того, что класс реализует интерфейс, осуществляется с помощью двоеточия, используемого также для указания наследования класса. Управляемый класс может наследовать от одного управляемого класса и, кроме этого, от одного или нескольких управляемых интерфейсов. В этом случае базовый класс должен указываться в списке первым, сразу после двоеточия. Заметим, что, в отличие от управляемых интерфейсов, наследование управляемых классов может быть только общедоступным.

_gc class HotelBroker : public Broker, public IHotellnfo,
// класс сборщика мусора - HotelBroker: общедоступный Брокер,
public IHotelAdmin, public IHotelReservation
{
...
};

В этом примере класс HotelBroker является производным от класса Broker (Брокер) и реализует интерфейсы IHotellnfo, IHotelAdmin и IHotelReservation. В HotelBroker должны быть реализованы все методы этих интерфейсов, либо непосредственно, либо используя реализацию, унаследованную от базового класса Broker (Брокер).
Подробно пример использования интерфейсов будет рассмотрен в этой главе несколько позже, когда мы возьмемся за реализацию второго шага создаваемой системы.
А сейчас в качестве небольшого примера вышеизложенного, рассмотрим программу Smalllnterface. Класс Account (Счет) реализует интерфейс IBasicAccount. В описании этого интерфейса демонстрируется синтаксис объявления свойства интерфейса.

//Account.h
_gc _interface IBasicAccount
// сборщик мусора - IBasicAccount
{
void Deposit(Decimal amount); // Депозит (Десятичное
// количество);
void Withdraw(Decimal amount); // Снять (Десятичное
// количество);
_property Decimal get_Balance(); // Десятичное число };
_gc class Account : public IBasicAccount
// сборщик мусора - класс Счет: IBasicAccount
{
private: // частный
Decimal balance; // Десятичный баланс public:
Account(Decimal balance) // Счет (Десятичный баланс)
{
this->balance = balance; // баланс
}
void Deposit(Decimal amount) // Депозит (Десятичное количество)
{
balance = balance + amount; // баланс = баланс + количество
}
void Withdraw(Decimal amount) // Снять (Десятичное количество)
{
balance = balance - amount; // баланс = баланс - количество
}
_property Decimal get_Balance() // Десятичное число
{
return balance; // баланс
}
};

Использование интерфейсов

Когда известно, что некоторый класс поддерживает определенный интерфейс, его методы можно вызывать с помощью указателя на экземпляр класса. Если же неизвестно, реализован ли интерфейс классом, можно попытаться выполнить приведение указателя на класс к указателю на интерфейс. И если класс не поддерживает данный интерфейс, при такой попытке возникнет исключение. В следующем примере, взятом из файла Smalllnterf асе. h, демонстрируется именно такой способ проверки.

try // попытка
{
IBasicAccount *pifc2 =
dynamic_cast<IBasicAccount *>(pacc2);
pifc2->Deposit(25); // Депозит
Console::WriteLine(
"balance = {0}", _box(pifc2->Balance)); // Баланс
}
catch (NullReferenceException *pe)
{
Console::WriteLine(
"IBasicAccount is not supported"); // IBasicAccount
// не поддерживается
Console::WriteLine(pe->Message); // Сообщение
}
}

В программе Small Inter face используются два почти одинаковых класса. Класс Account (Счет) поддерживает интерфейс IBasicAccount, а второй класс, NoAccount его не поддерживает. Оба класса имеют идентичные наборы методов и свойств. Приведем полностью содержимое файлов Smalllnterf асе. срр и Smalllnterf асе. h. Заметим, что в этой программе делаются попытки привести указатели на экземпляры классов Account (Счет) и NoAccount к указателю на интерфейс IBasicAccount.

//Smalllnterfасе.срр
fusing <mscorlib.dll>
using namespace System;
// использование пространства имен Система;
#include "Account.h"
#include "NoAccount.h"
#include "Smalllnterface.h"
void main() // главный
{
Smalllnterface::Main(); // Главный
}
//Smalllnterface.h
_gc class Smalllnterface
// класс сборщика мусора Smalllnterface
{
public:
static void Main() // Главный
{
Account *pacc - new Account(100); // новый Счет
// Использовать ссылку на класс
Console::WriteLine(
"balance = {0}", _box(pacc->Balance)); // Баланс
pacc->Deposit(25); // Депозит
Console::WriteLine(
"balance = {0}", _box(pacc->Balance)); // Баланс
// Использовать ссылку на интерфейс
IBasicAccount *pifc =
dynamic_cast<IBasicAccount *>(pacc); pifc->Deposit(25); // Депозит
Console::WriteLine(
"balance = {0}", _box(pifc->Balance)); // Баланс
// Теперь попробовать с классом,
// не реализующим
IBasicAccount NoAccount *pacc2 = new NoAccount(500);
// Использовать ссылку на класс
Console::WriteLine(
"balance = {0}", _box(pacc2->Balance)); // Баланс
pacc2->Deposit(25); // Депозит
Console::WriteLine(
"balance = {0}", _box(pacc2->Balance)); // Баланс
// Испробовать указатель на интерфейс try
// попытка
{
IBasicAccount *piba=
dynamic_cast<IBasicAccount *>(pacc2);
piba->Deposit(25); // Депозит
Console::WriteLine(
"balance = {0}", _box(piba->Balance)); // Баланс
}
catch (NullReferenceException *pe)
{
Console::WriteLine(
"IBasicAccount is not supported"); // IBasicAccount
//не поддерживается
Console::WriteLine(pe->Message); // Сообщение
}
}
};

В приведенном примере сначала мы имеем дело с классом Account (Счет), который поддерживает интерфейс IBasicAccount. В этом случае попытки вызвать методы интерфейса как с помощью указателя на класс, так и указателя на интерфейс, полученного в результате приведения, заканчиваются успешно. Далее мы имеем дело с классом NoAccount. Несмотря на то, что набор методов этого класса идентичен набору методов класса Account (Счет), в его описании не указано, что он реализует интерфейс IBasicAccount.

//NoAccount.h
_gc class NoAccount
// класс сборщика мусора NoAccount
{

При запуске этой программы возникает исключение NullReferenceException. Это происходит при попытке использовать указатель на интерфейс IBasicAccount, полученный в результате динамического приведения указателя на класс NoAccount. (Иными словами, исключение возникает при попытке приведения типа NoAccount * к данным типа указателя на интерфейс IBasicAccount *.) Если бы мы использовали обычное приведение типа в стиле С, то при подобной попытке возникло бы исключение InvalidCastException. Однако уже при компиляции такой программы было бы выдано предупреждение, что использование приведения типов в стиле С не рекомендуется.

balance = 100
balance = 125
balance = 150
balance = 500
balance = 525
IBasicAccount is not supported
Value null was found where an instance of an object was
required.

Вот перевод выдачи:

баланс = 100
баланс =125
баланс = 150
баланс = 500
баланс = 525
IBasicAccount не поддерживается
Пустой указатель там, где требуется указатель на объект.