Мы постоянно, что-то программируем. Например, доступ к элементам массива. При этому очень часто решения, которые мы с Вами реализуем являются частными. То есть для частного случая. Надо что то исправить начинаем писать снова. Плохо это. С++ позволяет нам делать универсальные решения. Вот как это реализуется мы с Вами и посмотрим. Идея вот в чем. мы хотим в программе использовать массив. Что мы делаем? Берем класс допустим CStringArray и начинаем. Но самое интересное что если вдруг не дай бог придется изменить базовый класс то надо исправлять кучу кода. Выход из данной ситуации в использовании механизмов виртуальных функций и наследовании. Давайте посмотрим схему.
У нас есть основной самый первый класс CBaseAbstract, в нем просто описаны функции, которые нам необходимы без их реализации. Вот такая пустышка.
class CBaseAbstract { public: CBaseAbstract(); virtual ~CBaseAbstract(); virtual void Add(CString s); virtual void Remove(int iIndex); virtual CString GetAt(int iIndex); virtual int GetCount(); }; CBaseAbstract::CBaseAbstract() {} CBaseAbstract::~CBaseAbstract() {} void CBaseAbstract::Add(CString s) {} void CBaseAbstract::Remove(int iIndex) {} CString CBaseAbstract::GetAt(int iIndex) {return "";} int CBaseAbstract::GetCount() {return 0;}
И есть класс, который умеет вызывать функции этой пустышки или класса наследника.
class CWork { public: CWork(CBaseAbstract *pointer); ~CWork(); void Add(CString s); void Remove(int iIndex); CString GetAt(int iIndex); int GetCount(); private: CBaseAbstract* cPointer; }; CWork::CWork(CBaseAbstract *pointer) { cPointer=pointer; } CWork::~CWork() {} void CWork::Add(CString s) { cPointer->Add(s); } void CWork::Remove(int iIndex) { cPointer->Remove(iIndex); } CString CWork::GetAt(int iIndex) { return cPointer->GetAt(iIndex); } int CWork::GetCount() { return cPointer->GetCount(); }
Ну, и теперь мы спокойно можем реализовывать любой класс как наследник от CBaseAbstract, перегружать его виртуальные функции, но работать в программе мы все равно будем с CWork. При том совершенно одинаково в не зависимости от того на какой физической базе класс.
#include "stdafx.h" #include "MFCArray.h" #include "StlArray.h" #include "work.h" #include "iostream.h" void main() { CMFCArray mfcArray; CStlArray stlArray; CWork cw1(&mfcArray); CWork cw2(&stlArray); cw1.Add("Hello"); cw2.Add("Hello"); cw1.Add("Abstract"); cw2.Add("Abstract"); cout << cw1.GetCount() << " " << cw2.GetCount() << endl; cout << cw1.GetAt(1) << " " << cw2.GetAt(1) << endl; }
Естественно, что классы CStlArray и CMFCArray я породил от CBaseAbstract, но внутренняя реализация каждого класса своя.
#include "BaseAbstract.h" #include "afxcoll.h" class CMFCArray : public CBaseAbstract { public: CString GetAt(int iIndex); int GetCount(); void Add(CString s); CMFCArray(); virtual ~CMFCArray(); private: CStringArray ca; }; #include "BaseAbstract.h" #include "iostream.h" #include "vector" #include "afxwin.h" using namespace std ; typedef vector<CString> STLStringArray; class CStlArray : public CBaseAbstract { public: CString GetAt(int iIndex); int GetCount(); void Add(CString s); CStlArray(); virtual ~CStlArray(); private: STLStringArray ca; };
Реализация методов совершенно тривиальная и Вы можете посмотреть ее в проекте. Использование данной технологии дает вам широкие возможности к повторному использованию кода. Например для баз данных создали свои классы CBaseAbstract и CBaseWork и работайте хоть с DAO хоть с ADO или еще с чем. С какой то черты, а точнее с класса в данном случае CBaseWork код Ваш меняться не будет при заменен метода доступа к данным. А значит и элементы управления универсальные и так далее. Вся работа будет сосредоточена на производном классе от CBaseAbstract.