Tôi đã cố gắng giải quyết vấn đề có thể lặp lại qua một số mảng văn bản khác nhau, tất cả chúng được lưu trữ trong một cơ sở dữ liệu lưu trữ bộ nhớ lớn struct
.
Sau đây đã được thực hiện bằng Visual Studio 2017 Community Edition trên ứng dụng thử nghiệm MFC. Tôi lấy ví dụ này làm ví dụ vì bài đăng này là một trong số đó tôi đã chạy qua cung cấp một số trợ giúp nhưng vẫn không đủ cho nhu cầu của tôi.
Việc struct
chứa dữ liệu cư trú bộ nhớ trông giống như sau. Tôi đã loại bỏ hầu hết các yếu tố vì lý do ngắn gọn và cũng không bao gồm Định nghĩa tiền xử lý được sử dụng (SDK được sử dụng là cho C cũng như C ++ và đã cũ).
Điều tôi quan tâm là làm các trình vòng lặp cho các WCHAR
mảng hai chiều khác nhau có chứa các chuỗi văn bản cho việc ghi nhớ.
typedef struct tagUNINTRAM {
// stuff deleted ...
WCHAR ParaTransMnemo[MAX_TRANSM_NO][PARA_TRANSMNEMO_LEN]; /* prog #20 */
WCHAR ParaLeadThru[MAX_LEAD_NO][PARA_LEADTHRU_LEN]; /* prog #21 */
WCHAR ParaReportName[MAX_REPO_NO][PARA_REPORTNAME_LEN]; /* prog #22 */
WCHAR ParaSpeMnemo[MAX_SPEM_NO][PARA_SPEMNEMO_LEN]; /* prog #23 */
WCHAR ParaPCIF[MAX_PCIF_SIZE]; /* prog #39 */
WCHAR ParaAdjMnemo[MAX_ADJM_NO][PARA_ADJMNEMO_LEN]; /* prog #46 */
WCHAR ParaPrtModi[MAX_PRTMODI_NO][PARA_PRTMODI_LEN]; /* prog #47 */
WCHAR ParaMajorDEPT[MAX_MDEPT_NO][PARA_MAJORDEPT_LEN]; /* prog #48 */
// ... stuff deleted
} UNINIRAM;
Cách tiếp cận hiện tại là sử dụng một khuôn mẫu để xác định một lớp proxy cho từng mảng và sau đó có một lớp lặp duy nhất có thể được sử dụng để lặp qua một mảng cụ thể bằng cách sử dụng một đối tượng proxy đại diện cho mảng.
Một bản sao của dữ liệu lưu trú bộ nhớ được lưu trữ trong một đối tượng xử lý việc đọc và ghi dữ liệu lưu trữ bộ nhớ từ / vào đĩa. Lớp này, CFilePara
chứa lớp proxy templated ( MnemonicIteratorDimSize
và lớp con mà nó được dẫn xuất, MnemonicIteratorDimSizeBase
) và lớp iterator , MnemonicIterator
.
Đối tượng proxy được tạo được gắn vào một đối tượng lặp để truy cập thông tin cần thiết thông qua một giao diện được mô tả bởi một lớp cơ sở mà từ đó tất cả các lớp proxy được dẫn xuất. Kết quả là có một loại lớp lặp duy nhất có thể được sử dụng với một số lớp proxy khác nhau vì các lớp proxy khác nhau đều hiển thị cùng một giao diện, giao diện của lớp cơ sở proxy.
Điều đầu tiên là tạo ra một tập hợp các mã định danh sẽ được cung cấp cho một nhà máy lớp để tạo đối tượng proxy cụ thể cho kiểu ghi nhớ đó. Các mã định danh này được sử dụng như một phần của giao diện người dùng để xác định dữ liệu cung cấp cụ thể mà người dùng quan tâm để xem và có thể sửa đổi.
const static DWORD_PTR dwId_TransactionMnemonic = 1;
const static DWORD_PTR dwId_ReportMnemonic = 2;
const static DWORD_PTR dwId_SpecialMnemonic = 3;
const static DWORD_PTR dwId_LeadThroughMnemonic = 4;
Lớp Proxy
Lớp proxy templated và lớp cơ sở của nó như sau. Tôi cần phải chứa một số loại wchar_t
mảng chuỗi văn bản khác nhau . Mảng hai chiều có số lượng ghi nhớ khác nhau, tùy thuộc vào loại (mục đích) của kiểu ghi nhớ và các loại ghi nhớ khác nhau có độ dài tối đa khác nhau, khác nhau giữa năm ký tự văn bản và hai mươi ký tự văn bản. Các mẫu cho lớp proxy dẫn xuất là phù hợp tự nhiên với mẫu yêu cầu số lượng ký tự tối đa trong mỗi lần ghi nhớ. Sau khi đối tượng proxy được tạo, sau đó chúng tôi sử dụng SetRange()
phương thức để chỉ định mảng ghi nhớ thực tế và phạm vi của nó.
// proxy object which represents a particular subsection of the
// memory resident database each of which is an array of wchar_t
// text arrays though the number of array elements may vary.
class MnemonicIteratorDimSizeBase
{
DWORD_PTR m_Type;
public:
MnemonicIteratorDimSizeBase(DWORD_PTR x) { }
virtual ~MnemonicIteratorDimSizeBase() { }
virtual wchar_t *begin() = 0;
virtual wchar_t *end() = 0;
virtual wchar_t *get(int i) = 0;
virtual int ItemSize() = 0;
virtual int ItemCount() = 0;
virtual DWORD_PTR ItemType() { return m_Type; }
};
template <size_t sDimSize>
class MnemonicIteratorDimSize : public MnemonicIteratorDimSizeBase
{
wchar_t (*m_begin)[sDimSize];
wchar_t (*m_end)[sDimSize];
public:
MnemonicIteratorDimSize(DWORD_PTR x) : MnemonicIteratorDimSizeBase(x), m_begin(0), m_end(0) { }
virtual ~MnemonicIteratorDimSize() { }
virtual wchar_t *begin() { return m_begin[0]; }
virtual wchar_t *end() { return m_end[0]; }
virtual wchar_t *get(int i) { return m_begin[i]; }
virtual int ItemSize() { return sDimSize; }
virtual int ItemCount() { return m_end - m_begin; }
void SetRange(wchar_t (*begin)[sDimSize], wchar_t (*end)[sDimSize]) {
m_begin = begin; m_end = end;
}
};
Lớp lặp
Bản thân lớp lặp như sau. Lớp này chỉ cung cấp chức năng lặp chuyển tiếp cơ bản, đó là tất cả những gì cần thiết tại thời điểm này. Tuy nhiên tôi hy vọng rằng điều này sẽ thay đổi hoặc được gia hạn khi tôi cần một cái gì đó bổ sung từ nó.
class MnemonicIterator
{
private:
MnemonicIteratorDimSizeBase *m_p; // we do not own this pointer. we just use it to access current item.
int m_index; // zero based index of item.
wchar_t *m_item; // value to be returned.
public:
MnemonicIterator(MnemonicIteratorDimSizeBase *p) : m_p(p) { }
~MnemonicIterator() { }
// a ranged for needs begin() and end() to determine the range.
// the range is up to but not including what end() returns.
MnemonicIterator & begin() { m_item = m_p->get(m_index = 0); return *this; } // begining of range of values for ranged for. first item
MnemonicIterator & end() { m_item = m_p->get(m_index = m_p->ItemCount()); return *this; } // end of range of values for ranged for. item after last item.
MnemonicIterator & operator ++ () { m_item = m_p->get(++m_index); return *this; } // prefix increment, ++p
MnemonicIterator & operator ++ (int i) { m_item = m_p->get(m_index++); return *this; } // postfix increment, p++
bool operator != (MnemonicIterator &p) { return **this != *p; } // minimum logical operator is not equal to
wchar_t * operator *() const { return m_item; } // dereference iterator to get what is pointed to
};
Nhà máy đối tượng proxy xác định đối tượng nào sẽ được tạo dựa trên định danh ghi nhớ. Đối tượng proxy được tạo và con trỏ trả về là loại lớp cơ sở tiêu chuẩn để có giao diện thống nhất bất kể phần nào trong các phần ghi nhớ khác nhau đang được truy cập. Các SetRange()
phương pháp được sử dụng để xác định đối tượng proxy phần tử mảng cụ proxy đại diện và phạm vi của các phần tử mảng.
CFilePara::MnemonicIteratorDimSizeBase * CFilePara::MakeIterator(DWORD_PTR x)
{
CFilePara::MnemonicIteratorDimSizeBase *mi = nullptr;
switch (x) {
case dwId_TransactionMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_TRANSMNEMO_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_TRANSMNEMO_LEN>(x);
mk->SetRange(&m_Para.ParaTransMnemo[0], &m_Para.ParaTransMnemo[MAX_TRANSM_NO]);
mi = mk;
}
break;
case dwId_ReportMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_REPORTNAME_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_REPORTNAME_LEN>(x);
mk->SetRange(&m_Para.ParaReportName[0], &m_Para.ParaReportName[MAX_REPO_NO]);
mi = mk;
}
break;
case dwId_SpecialMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_SPEMNEMO_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_SPEMNEMO_LEN>(x);
mk->SetRange(&m_Para.ParaSpeMnemo[0], &m_Para.ParaSpeMnemo[MAX_SPEM_NO]);
mi = mk;
}
break;
case dwId_LeadThroughMnemonic:
{
CFilePara::MnemonicIteratorDimSize<PARA_LEADTHRU_LEN> *mk = new CFilePara::MnemonicIteratorDimSize<PARA_LEADTHRU_LEN>(x);
mk->SetRange(&m_Para.ParaLeadThru[0], &m_Para.ParaLeadThru[MAX_LEAD_NO]);
mi = mk;
}
break;
}
return mi;
}
Sử dụng lớp Proxy và Iterator
Lớp proxy và trình vòng lặp của nó được sử dụng như được hiển thị trong vòng lặp sau để điền vào một CListCtrl
đối tượng với một danh sách ghi nhớ. Tôi đang sử dụng std::unique_ptr
để khi lớp proxy tôi không còn cần thiết và std::unique_ptr
vượt quá phạm vi, bộ nhớ sẽ bị xóa.
Những gì mã nguồn này làm là tạo một đối tượng proxy cho mảng bên trong struct
tương ứng với mã định danh ghi nhớ được chỉ định. Sau đó, nó tạo ra một trình vòng lặp cho đối tượng đó, sử dụng một phạm vi for
để điền vào CListCtrl
điều khiển và sau đó dọn sạch. Đây là tất cả các wchar_t
chuỗi văn bản thô có thể chính xác là số lượng phần tử mảng, vì vậy chúng tôi sao chép chuỗi vào bộ đệm tạm thời để đảm bảo văn bản không bị chấm dứt.
std::unique_ptr<CFilePara::MnemonicIteratorDimSizeBase> pObj(pFile->MakeIterator(m_IteratorType));
CFilePara::MnemonicIterator pIter(pObj.get()); // provide the raw pointer to the iterator who doesn't own it.
int i = 0; // CListCtrl index for zero based position to insert mnemonic.
for (auto x : pIter)
{
WCHAR szText[32] = { 0 }; // Temporary buffer.
wcsncpy_s(szText, 32, x, pObj->ItemSize());
m_mnemonicList.InsertItem(i, szText); i++;
}