C++ CLI dynamic_cast и множественное наследование (Windows Forms и интерфейсы)

Сценарий, с которым я работаю, выглядит следующим образом:

public interface INativeWindow { ... }

— это собственный оконный тип интерфейса, содержащий несколько необходимых базовых методов, которые необходимо реализовать, чтобы иметь минимальную поддержку окна (например, свертывание, восстановление и т. д.). Это интерфейс C#, принадлежащий проекту интерфейсов.

Теперь я хочу реализовать его в классе CLINativeWindow c++-cli:

public ref class CLINativeWindow: public SWF::NativeWindow, INativeWindow
{ 
 ...
}

Наконец, у меня есть еще один класс ref c++ cli, который имеет внутренний член типа CLINativeWindow и свойство-оболочку, которое возвращает дескриптор INativeWindow^:

virtual property INativeWindow^ OwnNativeWindow
                {
                    INativeWindow^ __clrcall get() sealed { return NativeWindow;}
                    void __clrcall set(INativeWindow^ value) { NativeWindow = dynamic_cast<CLINativeWindow^>(value);}
                }

Проблема здесь в том, что dynamic_cast не работает, равно как и неявное полиморфное преобразование вниз из метода получения свойства. Если я не дезинформирован, я думаю, что читал в нескольких местах, что в C++ с указателями normal такая ошибка действительно работает. Теперь, поскольку SWF::NativeWindow является классическим классом Windows Forms, собственным классом окна (извините за непреднамеренную аллитерацию), он должен иметь виртуальный метод, так же, как и интерфейс, поэтому для оператора динамического приведения не возникает проблем, поскольку задействовано полиморфное наследование. Я ошибаюсь или это просто невозможно в CLI dotNet C++?

ИЗМЕНИТЬ дополнительный код:

public ref class ExampleForSO
{
  CLINativeWindow^ NativeWindow;


 virtual property INativeWindow^ OwnNativeWindow
                    {
                        INativeWindow^ __clrcall get() sealed { return NativeWindow;}
                        void __clrcall set(INativeWindow^ value) { NativeWindow = dynamic_c

ast<CLINativeWindow^>(value);}
            }
}

Ошибки возникают во время компиляции, и они утверждают, что преобразование/приведение не может быть выполнено как для геттера, так и для сеттера (т.е. невозможно преобразовать из B^ в A^ и из B^ в A^). ОБНОВЛЕНИЕ Если классы находятся в разных файлах, реализация свойства в заголовке не годится. Реализация его в отдельном исходном файле .cpp больше не вызывает ошибки времени компиляции и работает так, как хотелось бы.


person teodron    schedule 06.07.2012    source источник


Ответы (1)


Здесь нет множественного наследования. Ваш CLINativeWindow наследуется от одного класса: SWF::NativeWindow, а также реализует интерфейс INativeWindow.

Вы не предоставили достаточно информации (какие ошибки вы получаете? пример кода, который можно вставить в VS, чтобы воспроизвести проблему?), но в целом в коде, который вы разместили, нет ничего плохого.

Я предполагаю, что ваш NativeWindow объявлен как:

CLINativeWindow NativeWindow;

без столь необходимого ^. Попробуйте объявить это как:

CLINativeWindow^ NativeWindow;

ИЗМЕНИТЬ

Следующее компилируется чисто для меня:

public interface class INativeWindow
{};

public ref class SWFNativeWindow
{};

public ref class CLINativeWindow : SWFNativeWindow, INativeWindow
{};

public ref class NWHolder
{
public:
    virtual property INativeWindow^ OwnNativeWindow
    {
        INativeWindow^ __clrcall get() sealed { return nativeWindow_; }
        void __clrcall set(INativeWindow^ w) { nativeWindow_ = dynamic_cast<CLINativeWindow^>(w); }
    }

private:
    CLINativeWindow^ nativeWindow_;
};
person Bojan Resnik    schedule 06.07.2012
comment
Я включил спецификатор дескриптора в тип. Я думал, что в C++-CLI нет такой концепции реализации интерфейса, это просто похоже на наследование идиомы абстрактного класса C++. Вот почему я указал множественное наследование в заголовке. Более того, можно ли использовать оператор dynamic_cast для преобразования класса реализации в его дескриптор interface... когда... производный класс также наследует другой класс? Это главная проблема, и я не имею ни малейшего представления о том, что я нашел в Интернете. Спасибо! - person teodron; 06.07.2012
comment
Спасибо за обновление, вместо класса SWFNativeWindow ref, не могли бы вы попробовать: System::Windows::Forms::NativeWindow вместо этого? Все должно быть в порядке, так как WndProc является виртуальным защищенным методом... но для меня это не так. - person teodron; 06.07.2012
comment
Спасибо за макет кода. Это именно тот иллюстративный сценарий, о котором я говорил, за исключением крошечной разницы: я использую System::Windows::Forms::NativeClass, а SWF — это просто псевдоним пространства имен. В этом случае приведение не работает (но оно должно работать так же, как у вас). Также я подумал, что для работы приведения с полиморфизмом требуется хотя бы один виртуальный метод в базовых классах. - person teodron; 06.07.2012
comment
У меня все еще компилируется даже с System::Windows::Forms::NativeWindow. Попробуйте скомпилировать пример кода здесь, а затем сравните с фактическим кодом, который у вас есть. Что касается dynamic_cast, то, что вы говорите, верно для C++. Однако для управляемых типов в C++/CLI dynamic_cast является эквивалентом ключевого слова C# as. - person Bojan Resnik; 06.07.2012
comment
Спасибо, попробовал, у меня тоже компилируется без проблем, но в пустой проект, и в основной cpp файл. Думаю проблема как-то в другом. - person teodron; 06.07.2012