gpt4 book ai didi

c++-cli - 如何在 c++/cli 中调用基类索引器属性?

转载 作者:行者123 更新时间:2023-12-04 10:53:13 28 4
gpt4 key购买 nike

我正在尝试实现一个继承自泛型 List<T> 的类类(class):

Class MyList::List<MyClass>

我想调用 List<T>::Item[Int32] indexer 属性在我的一种方法中,但我不知道该怎么做。

我试过 List<MyClass>::[i]List<MyClass>::Item[i] ,但两者都不起作用。

我知道,从 List<MyClass> 调用其他方法,例如 Add ,我可以做 List<MyClass>::Add(myInstance) .

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

最佳答案

List<T>.Item[Int32] 是一个默认的索引器,你可以做 this[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;
}

或者,如果您愿意,可以使用“默认索引器”属性名称 default[i]明确:
if (this->default[i] != nullptr)
nonNull++;
List<MyClass ^>::default[i]也是有效的,可用于在覆盖索引器本身时调用基本索引器。

见: How to: Use Properties in C++/CLI: Indexed properties .

在您写的评论中,您确实打算覆盖 List<T>.Item[Int32]默认索引器:

I intend to implement a class that stores a list of images. Depending on some conditions, my indexer would either return the raw image or a processed image.



如果是这样,我不建议从 List<T> 继承因为 List<T>.Item[Int32] 非虚拟 并且不打算被覆盖。因此,您只能通过 interface re-implementation 隐藏它。 .但这会使您的应用程序面临一个可能的错误:如果您的 MyList永远向上转换为基类 List<MyClass ^> ,则不会调用替换索引器。更糟糕的是,似乎 List<T>.GetEnumerator() 返回的枚举数不会调用您的替换索引器,因此只需遍历 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方法调用 ProcessItem()在退回之前进行处理。 (您的图像处理将在此处进行;在示例中, bool 设置为 true。)

现在考虑以下单元测试:
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.

当第二个和第四个断言通过时,第一个和第三个断言失败,因为替换 get()方法没有被调用。这真的是无法避免的;通过 new 重新实现接口(interface)关键字实际上并没有覆盖基本实现,它在 vtable 中创建一个带有新插槽的新实现。见: new (new slot in vtable) (C++/CLI and C++/CX) .

那么,您有哪些选择?

首先,如果可以在 时进行必要的图像处理。添加 图像到集合,你可以从 System.Collections.ObjectModel.Collection<T> 继承它提供了 protected 虚拟方法,每当从集合中添加或删除项目时都会调用这些方法。 (这是 ObservableCollection<T> 的基类。)

因此,如果我们定义 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;
}
};

然后所有四个断言现在都通过了:
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

其次,如果图像处理必须在 get()方法,您可以使用 decorator pattern并创建自己的自定义集合实现 List<MyClass ^ > 包装底层 List<MyClass ^>并在其自己的默认索引器、枚举器 CopyTo() 中进行必要的处理以及根据需要访问项目的其他方法:
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
};

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

关于c++-cli - 如何在 c++/cli 中调用基类索引器属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59365870/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com