C++ cli 如何在c++/cli?

C++ cli 如何在c++/cli?,c++-cli,C++ Cli,我正在尝试实现一个从泛型列表继承的类: Class MyList::List<MyClass> Class MyList::List 我想在我的一个方法中调用List::Item[Int32]indexer属性,但我想不出该怎么做 我尝试了List::[I]和List::Item[I],但两者都不起作用 我知道,要从List调用其他方法,例如Add,我只需执行List::Add(myInstance) (在我的真实代码中,我打算实现一个存储图像列表的类。根据某些条件,我的索引器将

我正在尝试实现一个从泛型
列表继承的类:

Class MyList::List<MyClass>
Class MyList::List
我想在我的一个方法中调用
List::Item[Int32]
indexer属性,但我想不出该怎么做

我尝试了
List::[I]
List::Item[I]
,但两者都不起作用

我知道,要从
List
调用其他方法,例如
Add
,我只需执行
List::Add(myInstance)

(在我的真实代码中,我打算实现一个存储图像列表的类。根据某些条件,我的索引器将返回原始图像或处理后的图像。因此,我需要在索引器的getter中包含一些逻辑。)

因为是默认索引器,所以您可以执行
此[I]
。例如:

public ref class MyList : System::Collections::Generic::List<MyClass ^>
{
public:
    int CountNonNull();
};

int MyList::CountNonNull()
{
    int nonNull = 0;
    for (int i = 0; i < Count; i++)
    {
        if (this[i] != nullptr)
            nonNull++;
    }
    return nonNull;
}
List::default[i]
也有效,可以在重写索引器本身时用于调用基索引器

请参阅:


在您写的注释中,您确实希望覆盖
列表。项[Int32]
默认索引器:

我打算实现一个存储图像列表的类。根据某些条件,索引器将返回原始图像或已处理图像

如果是这样,我不建议继承自
列表
,因为它是非虚拟的,不打算被重写。因此,您只能通过以下方式隐藏它。但这会让你的应用程序面临一个可能的错误:如果你的
MyList
被上溯到基类
列表
,那么替换索引器将不会被调用。更糟糕的是,返回的枚举器似乎不会调用替换索引器,因此简单地遍历
MyList
将导致返回未处理的项

为了理解我的意思,考虑下面的合成例子:

ref class MyList;

public ref class MyClass
{
public:
    property bool Processed;
};

public ref class MyList : List<MyClass ^>, IList<MyClass ^>
{
public:
   // default indexer
    virtual property MyClass^ default[int] 
    {
        MyClass^ get(int index) new = IList<MyClass ^>::default::get  // hiding + interface reimplementation of default::get method
        { 
            MyClass^ item = List<MyClass ^>::default[index]; // Call base default indexer
            item = ProcessItem(item);                        // Add your custom logic here
            return item;                                     // return the item
        }
        void set(int index, MyClass^ value) new = IList<MyClass ^>::default::set // hiding + interface reimplementation of default::set method
        {
            List<MyClass ^>::default[index] = value;         // Call base default indexer
        }
    }

private:
    MyClass^ ProcessItem(MyClass ^item)
    {
        // Add your custom logic here
        if (item != nullptr)
            item->Processed = true;
        return item;
    }
};
当第二个和第四个断言通过时,第一个和第三个断言失败,因为没有调用替换
get()
方法。这真的是无法避免的;通过
new
关键字重新实现接口实际上并不会覆盖基本实现,而是在vtable中创建一个新的实现,其中包含一个新的插槽。请参阅:

那么,你有什么选择

首先,如果在将图像添加到集合中时可以执行必要的图像处理,则可以从中继承,该方法提供受保护的虚拟方法,每当从集合中添加或删除项时都会调用这些方法。(这是
ObservableCollection
的基类)

因此,如果我们将
MyList
定义如下:

public ref class MyList : Collection<MyClass ^>
{
protected:
    virtual void InsertItem(int index, MyClass ^ item) override
    {
        Collection<MyClass ^>::InsertItem(index, ProcessItem(item));
    }

    virtual void SetItem(int index, MyClass ^ item) override
    {
        Collection<MyClass ^>::InsertItem(index, ProcessItem(item));
    }

private:
    MyClass^ ProcessItem(MyClass ^item)
    {
        // Add your custom logic here
        if (item != nullptr)
            item->Processed = true;
        return item;
    }
};

现在,基础列表包含在翻译列表中,不可能访问“原始”图像。

是否在派生类中实现索引器?是的。我打算实现一个存储图像列表的类。根据某些条件,我的索引器将返回原始图像或已处理的图像。然后不要从
列表继承,它不是为其索引器被覆盖而设计的。.NETFramework由派生类支持,但不能使基类在内部调用替换方法。相反,考虑从<代码> Stase.Copy.ObjutMask.Cube < /C>中继承,它是为实现此目的而设计的,因为它允许您重写和<代码>插入式(int index,t item)< />代码。或者创建自己的类来实现
IList
,并包含一个内部
列表(装饰器或适配器模式)。什么意思
List
不是为其索引器被重写而设计的?这是因为它是高度优化的,覆盖它会影响性能吗?谢谢<代码>列表::默认[i]
是我要找的!我在谷歌上搜索时读过这个问题。就我而言,我非常确信继承比组合更好。这很有帮助。谢谢
MyList ^list = gcnew MyList();

list->Add(gcnew MyClass());
for each (MyClass^ item in list)
    Debug::Assert(item->Processed); // FAILS because enumerator doesn't call indexer!

list->Add(gcnew MyClass());
Debug::Assert(list[list->Count-1]->Processed); // Passes because re-implemented Add() was called.

// Upcast to base class
List<MyClass ^>^ baseList = list;
baseList->Add(gcnew MyClass());
Debug::Assert(baseList[list->Count-1]->Processed); // FAILS because re-implemented Add() was NOT called!

// Upcast to interface
IList<MyClass ^>^ iList = list;
iList->Add(gcnew MyClass());
Debug::Assert(iList[iList->Count-1]->Processed); // Passes because re-implemented Add() was called.
public ref class MyList : Collection<MyClass ^>
{
protected:
    virtual void InsertItem(int index, MyClass ^ item) override
    {
        Collection<MyClass ^>::InsertItem(index, ProcessItem(item));
    }

    virtual void SetItem(int index, MyClass ^ item) override
    {
        Collection<MyClass ^>::InsertItem(index, ProcessItem(item));
    }

private:
    MyClass^ ProcessItem(MyClass ^item)
    {
        // Add your custom logic here
        if (item != nullptr)
            item->Processed = true;
        return item;
    }
};
MyList ^list = gcnew MyList();

list->Add(gcnew MyClass());
for each (MyClass^ item in list)
    Debug::Assert(item->Processed); // Passes

list->Add(gcnew MyClass());
Debug::Assert(list[list->Count-1]->Processed); // Passes

// Upcast to base class
Collection<MyClass ^>^ baseList = list;
baseList->Add(gcnew MyClass());
Debug::Assert(baseList[list->Count-1]->Processed); // Passes

// Upcast to interface
IList<MyClass ^>^ iList = list;
iList->Add(gcnew MyClass());
Debug::Assert(iList[iList->Count-1]->Processed); // Passes      
public ref class MyList : IList<MyClass ^>
{
private:
    List<MyClass ^> list;

public:
    MyList()
    {
        list = gcnew List<MyClass ^>();
    }

    virtual property MyClass^ default[int] 
    {
        MyClass^ get(int index)
        {
            MyClass^ item = list[int];
            item = ProcessItem(item); // Add your custom logic here                
            return item;                                     
        }
        void set(int index, MyClass^ value)
        {
            list[index] = value;
        }
    }

    // Implement all other methods as required.
    virtual property int Count { int get() { return list->Count; } }

    // Etc
};