Переключение на Главную Страницу Страницы: 1 ОтправитьПечать
Обычная тема Шаблонная функция класса, использующая приват-поля (число прочтений - 3967 )
artbear
1c++ developer
1c++ moderator
Отсутствует


Эх, дайте что-нибудь новенькое
да полезное потести

Сообщений: 6303
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Шаблонная функция класса, использующая приват-поля
07. Мая 2008 :: 12:50
Печать  
Народ, помогите решить задачу.
У CComponentClass есть публичный шаблонный метод
Код
Выбрать все
	template <class T>
	BOOL GetBaseClass(T** ppT) const
	{
		for (CONST_ITER_CONT iter = vecOfBaseCont.begin(); iter != vecOfBaseCont.end(); ++iter)
		{
			CBLContext *pCont = *iter;
			if (GetBaseClassFromContext(pCont, ppT))
				return TRUE;
			if (pCont->GetRuntimeClass() == RUNTIME_CLASS(CComponentClass))
			{
				if (static_cast<CComponentClass*>(pCont)->GetBaseClass(ppT))
					return TRUE;
			}
			else
			{
				T* p = dynamic_cast<T*>(pCont);
				if (p)
				{
					*ppT = p;
					return TRUE;
				}
			}
		}
		return FALSE;
	};
 


Который получает базовый класс, являющийся нужным типом.
Этот метод используется для наследников ТП и АктивИкс.

Второй день ничего в голову не приходит, кроме как описания 2-х отдельных методов для наследников ТП и АктивИкс, а точнее, спец.интерфейсов для них.

Вопрос: каким образом можно спрятать детали реализации класса (vecOfBaseCont и итераторы) для инкапсуляции и оставить шаблонную функцию рабочей.


Или я туплю?

PS Клиентский код, например, такой
Код
Выбрать все
	CV7Control* pV7Control = NULL;

	if (IS_BLTYPE(rValue, CComponentClass))
	{
		pUDC = rValue.GetContext();
		if (!static_cast<CComponentClass*>(pUDC)->GetBaseClass(&pV7Control))
			RuntimeError("Не удалось определить класс ЭУ среди родителей класса '%s'.", pUDC->GetTypeString());
	}
	else
	{
		pV7Control = dynamic_cast<CV7Control*>(rValue.GetContext());
		if (!pV7Control)
			RuntimeError("Класс '%s' не является ЭУ.", rValue.GetTypeString());
	}
 

  

OpenConf developer :: http://openconf.1cpp.ru&&FormEx developer :: http://formex.dorex.ru&&1C++ active developer &amp;&amp; tester :: www.1cpp.ru
Наверх
GTalkSkype/VoIPICQ  
IP записан
 
artbear
1c++ developer
1c++ moderator
Отсутствует


Эх, дайте что-нибудь новенькое
да полезное потести

Сообщений: 6303
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Шаблонная функция класса, использующая приват-
Ответ #1 - 07. Мая 2008 :: 13:08
Печать  
Или дать доступ к базовым классам в виде коллекции-копии ?
Например, предоставить публичный метод
boost::shared_ptr<std::vector<CSafeContextPtr<CBLContext> > > CComponentClass::GetBaseClassCollection() const;
а клиенты класса уже самостоятельно обходят коллекцию и получают нужную инфу?
В этом случае приватные данные классы не затрагиваются, но клиент получает возможность делать с базовым классом многое.

Вроде неплохой вариант, правда, по производительности тяжеловатый, похоже Печаль
  

OpenConf developer :: http://openconf.1cpp.ru&&FormEx developer :: http://formex.dorex.ru&&1C++ active developer &amp;&amp; tester :: www.1cpp.ru
Наверх
GTalkSkype/VoIPICQ  
IP записан
 
artbear
1c++ developer
1c++ moderator
Отсутствует


Эх, дайте что-нибудь новенькое
да полезное потести

Сообщений: 6303
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Шаблонная функция класса, использующая приват-
Ответ #2 - 07. Мая 2008 :: 13:19
Печать  
Или сделать простенький публичный итератор для получения доступа к коллекции базовых классов и предоставить его клиентам?
Т.е. метод
Код
Выбрать все
const CComponentClass::СBaseClassIterator CComponentClass::GetBaseClassIterator() const;
 



интерфейс итератора прост донельзя Улыбка
Код
Выбрать все
class СBaseClassIterator
{
public:
	void Next(); // ++
	bool IsEnd() const; // для проверки в цикле
	const CSafeContextPtr<CBLContext> Get() const; // сам объект
private:
	CBaseClassIterator(CComponentClass*);
};
 

  

OpenConf developer :: http://openconf.1cpp.ru&&FormEx developer :: http://formex.dorex.ru&&1C++ active developer &amp;&amp; tester :: www.1cpp.ru
Наверх
GTalkSkype/VoIPICQ  
IP записан
 
kms
1c++ power user
1c++ moderator
Отсутствует


я хочу, чтоб сюда проложили
дорогу оттуда...

Сообщений: 4632
Зарегистрирован: 19. Мая 2006
Re: Шаблонная функция класса, использующая приват-
Ответ #3 - 07. Мая 2008 :: 19:05
Печать  
Артур, время, видать, позднее, но как-то не понятно пока.
Этот шаблон уже работает для наследников ТП и АктивИкс.
А чего ему не хватает тогда?
  

De quelle planète es-tu?
Наверх
 
IP записан
 
orefkov
1c++ developer
1c++ moderator
Отсутствует


I Love YaBB 2!

Сообщений: 896
Зарегистрирован: 20. Мая 2006
Re: Шаблонная функция класса, использующая приват-
Ответ #4 - 08. Мая 2008 :: 05:05
Печать  
Ну, в своем проекте для возможности обхода иерерхии объектов я пользуюсь таким велосипедом:
Код
Выбрать все
// ctxtree.h
#pragma once

// Заголовок интерфейса для обхода древовидной структуры объектов.
// Если ваш класс, реализующий CBLContext, имеет иерархию, он должен реализовать и этот интерфейс.
struct IContextTree
{
	// Получить количество базовых объектов.
	virtual DWORD GetBaseObjCount() = 0;
	// Получить имя базового объекта по индексу.
	virtual CString GetBaseObjName(DWORD idx) = 0;
	// Получить базовый объект по индексу.
	virtual CBLContext* GetBaseObj(DWORD idx) = 0;
	// Для upcast'а
	virtual CBLContext* GetDerivedObj() = 0;
};

// Набор различных методов приведения контекстов
struct CastContext
{
	// Общая реализация обхода дерева с проверкой узлов передаваемым функтором
	template<typename Op>
	static CBLContext* DoCast(CBLContext* pCont, Op& op)
	{
		if(op.CheckContext(pCont))
			return pCont;
		IContextTree* pTree;
		try{
			if(!(pTree = dynamic_cast<IContextTree*>(pCont)))
				return NULL;
		}catch(...){ return NULL; }

		for(DWORD idx = 0, nBases = pTree->GetBaseObjCount(); idx < nBases ; idx++)
		{
			CBLContext* pBaseObj = pTree->GetBaseObj(idx);
			if(op.CheckBase(pTree, idx, pBaseObj))
				return pBaseObj;
			if(pBaseObj = DoCast(pBaseObj, op))
				return pBaseObj;
		}
		return NULL;
	}
	// Пустой функтор
	struct by_empty
	{
		BOOL CheckContext(CBLContext* pCont) {return FALSE; }
		BOOL CheckBase(IContextTree* pTree, DWORD idx, CBLContext* pCont) { return FALSE; }
	};
	// Функтор для поиска контекста по CRunTimeClass
	struct by_rtc : by_empty
	{
		const CRuntimeClass* pRTC;
		by_rtc(const CRuntimeClass* p) : pRTC(p){}
		BOOL CheckContext(CBLContext* pCont) {return pCont->GetRuntimeClass()->IsDerivedFrom(pRTC); }
	};
	// Функтор для поиска контекста по названию класса в CRunTimeClass
	struct by_rtc_name : by_empty
	{
		const CString& strName;
		by_rtc_name(const CString& s) : strName(s){}
		BOOL CheckContext(CBLContext* pCont) {return 0 == strName.CompareNoCase(pCont->GetRuntimeClass()->m_lpszClassName); }
	};
	// Функтор для поиска контекста по названию базового класса
	// внимание: поиск осуществляется сразу с базовых классов, сам класс на имя не проверяется
	struct by_base_name : by_empty
	{
		const CString& strName;
		by_base_name(const CString& s) : strName(s){}
		BOOL CheckBase(IContextTree* pTree, DWORD idx, CBLContext* pCont)
			{ return 0 == strName.CompareNoCase(pTree->GetBaseObjName(idx)); }
	};
	// Функтор для поиска контекста, реализующего интерфейс, доступный через динамиккаст
	template<typename T>
	struct by_dynamic_cast : by_empty
	{
		T*& pResult;
		by_dynamic_cast(T*& p) : pResult(p){}
		BOOL CheckContext(CBLContext* pCont)
		{
			try{
				pResult = dynamic_cast<T*>(pCont);
			}catch(...){ return FALSE; }
			return pResult != NULL;
		}
	};

	// Собственно, методы приведения

	// Upcast - получить конечный класс.
	static CBLContext* Up(CBLContext* pCont)
	{
		IContextTree* pTree;
		for(;;)
		{
			try{
				if(!(pTree = dynamic_cast<IContextTree*>(pCont)))
					break;
			}catch(...){ break; }
			CBLContext* pDerived = pTree->GetDerivedObj();
			if(!pDerived)
				break;
			pCont = pDerived;
		}
		return pCont;
	}

	// Приведение по CRunTimeClass'у
	static CBLContext* ByRTC(CBLContext* pCont, const CRuntimeClass* pRTC)
	{
		return DoCast(pCont, by_rtc(pRTC));
	}
	// Приведение по названию в CRunTimeClass'е
	static CBLContext* ByRTCName(CBLContext* pCont, const CString& strName)
	{
		return DoCast(pCont, by_rtc_name(strName));
	}
	// Приведение по имени базового класса
	static CBLContext* ByBaseName(CBLContext* pCont, const CString& strName)
	{
		return DoCast(pCont, by_base_name(strName));
	}
	// Приведение через dynamic_cast к заданному типу
	template<typename T>
	static CBLContext* Dynamic(CBLContext* pCont, T*& pResult)
	{
		return DoCast(pCont, by_dynamic_cast<T>(pResult));
	}
};
 


  
Наверх
 
IP записан
 
orefkov
1c++ developer
1c++ moderator
Отсутствует


I Love YaBB 2!

Сообщений: 896
Зарегистрирован: 20. Мая 2006
Re: Шаблонная функция класса, использующая приват-
Ответ #5 - 08. Мая 2008 :: 05:13
Печать  
Можно в CComponentClass реализовать этот интерфейс, спрятав в него все эти векторы.
  
Наверх
 
IP записан
 
artbear
1c++ developer
1c++ moderator
Отсутствует


Эх, дайте что-нибудь новенькое
да полезное потести

Сообщений: 6303
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Шаблонная функция класса, использующая приват-
Ответ #6 - 08. Мая 2008 :: 06:00
Печать  
orefkov писал(а) 08. Мая 2008 :: 05:13:
Можно в CComponentClass реализовать этот интерфейс, спрятав в него все эти векторы.

Лады, подумаю.
kms
Я хочу спрятать реализацию класса CComponentClass, оставив только его интерфейс для публичного использования.
А упомянутая функция как раз показывает внутренности класса Печаль
  

OpenConf developer :: http://openconf.1cpp.ru&&FormEx developer :: http://formex.dorex.ru&&1C++ active developer &amp;&amp; tester :: www.1cpp.ru
Наверх
GTalkSkype/VoIPICQ  
IP записан
 
artbear
1c++ developer
1c++ moderator
Отсутствует


Эх, дайте что-нибудь новенькое
да полезное потести

Сообщений: 6303
Местоположение: Москва
Зарегистрирован: 19. Мая 2006
Пол: Мужской
Re: Шаблонная функция класса, использующая приват-
Ответ #7 - 08. Мая 2008 :: 06:18
Печать  
orefkov
Большое спасибо.
Класс CastContext очень понравился.
  

OpenConf developer :: http://openconf.1cpp.ru&&FormEx developer :: http://formex.dorex.ru&&1C++ active developer &amp;&amp; tester :: www.1cpp.ru
Наверх
GTalkSkype/VoIPICQ  
IP записан
 
Переключение на Главную Страницу Страницы: 1
ОтправитьПечать