Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #30 : 20-11-2010 18:14 »   | 
								
								 | 
							  
							 
							имя он явно промазал ) Подправлено 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							mag
							
								Интересующийся 
								
								 
								  Offline
								Пол:   
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #31 : 22-11-2010 08:35 »   | 
								
								 | 
							  
							 
							Антон (LogRus), объясни чего я недопонял в первом варианте. >> 0. ... (со всеми типами и именами, можно макрос для упрощения задачи)... далее тест поочереди дёргает каждый из методов заглушки Пусть исходный интерфейс ITest содержит одну функцию. Тогда его проверка class CTest : public ITest {     void F () { printf ("void F ();\n" } };
      // ...     CTest ct1;     ITest * aTest = & ct1;     aTest->F ();
  и в логе получаем void F (); Далее во второй версии добавляем virtual void F (int) = 0; class CTest : public ITest {         void F () { printf ("void F ();\n" }         void F (int) { printf ("void F (int);\n" } };
  Его проверка     CTest ct1;     ITest * aTest = & ct1;     aTest->F ();     aTest->F ((int)0);
  Даёт в результате корректный но неправильный лог (перегруженная функция должна идти раньше) void F (); void F (int);  Алексей1153++  за имена спасибо. И сорри автору. А куда делось сообщение (имя не смогу воспроизвести) о функции явного получения номера функции? После некоторой его доработки мне удалось получить и номера для функций  с номером выше 32?  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 22-11-2010 08:40 от mag »
								 | 
								
									 
									Записан
								 | 
							  
							 
							Чего-бы ты ни сделал, ты всегда чего-нибудь не сделал... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									«  Ответ #32 : 22-11-2010 08:57 »    | 
								
								 | 
							  
							 
							mag, хм, его за это имя как раз и забанил. Ну и за неинтерактивность. Зря ? 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							mag
							
								Интересующийся 
								
								 
								  Offline
								Пол:   
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #33 : 22-11-2010 09:19 »   | 
								
								 | 
							  
							 
							Алексей1153++, Я уж не знаю досконально всех правил данного форума, но если не вдаваться в тонкости реализации и возможной тупиковости данного направления (кто-знает как будут выглядеть указатели на функции класса уже завтра или даже сегодня с другими флажками компилятора?), то это сообщение давало явный ответ на явный вопрос в заголовке темы. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Чего-бы ты ни сделал, ты всегда чего-нибудь не сделал... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #34 : 22-11-2010 09:31 »   | 
								
								 | 
							  
							 
							значит, я поторопился (
  ну а указатели будут выглядеть так же - хранилище адреса. Тут, мне кажется, ничего не поменяешь 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							mag
							
								Интересующийся 
								
								 
								  Offline
								Пол:   
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #35 : 22-11-2010 10:35 »   | 
								
								 | 
							  
							 
							Алексей1153++,  >> ну а указатели будут выглядеть так же - хранилище адреса. Тут, мне кажется, ничего не поменяешь Я не совсем это имел ввиду. Речь идёт об указателях на функцию класса, в том числе виртуальную, которая представляет собой: void (ITest:: * pFunc) () = &ITest::F; В результате pFunc указывает на адрес, где расположена функция для вызова функции F, с учётом подготовки параметров, передачи this и смещения данной функции в виртуальной таблице. В виртуальной таблице всё останется как и прежде (в том числе благодаря COM'у), а вот это место вызова может изменяться. Как изменяется оно сейчас, например, для Debug и Release версии.
  Если нельзя вернуть удалённые сообщения, то просьба опубликовать хотя бы имя этого респондента. Я опубликую свой вариант функции и выражу ему свою благодарность. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 22-11-2010 10:41 от mag »
								 | 
								
									 
									Записан
								 | 
							  
							 
							Чего-бы ты ни сделал, ты всегда чего-нибудь не сделал... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #36 : 22-11-2010 18:05 »   | 
								
								 | 
							  
							 
							mag,  vydtdrt
  бан отменил, почту щас в ЛС тебе напишу 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #37 : 23-11-2010 05:57 »   | 
								
								 | 
							  
							 
							Даёт в результате корректный но неправильный лог (перегруженная функция должна идти раньше) void F (); void F (int);
  задача стоит очень просто: проверить, что дёргая методы классы через старый интерфейс будут дёргаться именно те методы которые дёргались и ранее, поэтому: 1. порядок в котором ты вызываешь методы не имеет значения для теста 2. твой код тест может работать не верно, т.к. компилятору в этой точке доступна реализация класса и он с радостью забивает на механизм виртуализации, именно по этому я предложил, разделить тест на 2 модуля. еще раз у нас есть 4 модуля: 1. тест для старого интерфейса 2. длл реализующая старый интерфейс 3. тест для нового интерфейса 4. длл реализующая новый интерфейс запускаем 1+2, затем 1+3, далее сравниваем логи запускаем 1+4 смотрим, что не падает на каких-то формальных проверках (которые захочется добавить) что касается указателей на методы класса (что-то в первый раз в них смутило, ну да ладно), то вот примерчик #include <iostream> #include <sys/time.h>
  class I { public:     virtual void a() = 0;     virtual void b() = 0;     virtual void c() = 0;     virtual void a(int) = 0; };
  class A : public I { public:     virtual void c() {};         virtual void b() {};         virtual void a() {};     virtual void a(int) {}; };
  int main (int argc, char * const argv[]) {
      typedef void(I::*PI)();     PI ia = &I::a;     PI ib = &I::b;     PI ic = &I::c;
      typedef void(A::*PA)();     PA aa = &A::a;     PA ab = &A::b;     PA ac = &A::c;     std::cout << sizeof(ia) << "\n";          printf("I::a=%lld I::b=%lld I::c=%lld\n", ia, ib, ic);     printf("A::a=%lld A::b=%lld A::c=%lld\n", aa, ab, ac);     return 0; }
  у меня 64-х битная платформа и GCC, поэтому указатели 64 бита и соотвествующий им printf. не сложными вычислениями получаем номер метода n = (aa - 1)/sizeof(aa), отсчёт от нуля но по мне, это не верный способ для промышленного ПО, но как способ раньнего оповещения о возможных проблемах вполне себе метод.  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							mag
							
								Интересующийся 
								
								 
								  Offline
								Пол:   
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #38 : 23-11-2010 06:43 »   | 
								
								 | 
							  
							 
							В результате некоторых изысканий для решения исходной задачи был найден следующий вариант. Проверено для VS-2008, в том числе для статических и невиртуальных функций класса. Особая благодарность  vydtdrt - это его идея. Я её лишь слегка доработал. Впрочем, все вопросы на тему "почему это работает?" тоже к нему. Привожу свой вариант функции, так как исходный текст содержал операторы типа *++++++++f и *o ^= *o, которые являясь совершенно законными с точки зрения языка (и возможно более эффективные с точки зрения быстродействия) понятны далеко не всякому программисту. bool GetFunctionIndex (int * pIndex, ...) {     va_list argList;     va_start (argList, pIndex);     unsigned char * pCall = (unsigned char*) va_arg(argList, void *); #ifdef _DEBUG     pCall += 5 + *(int*)& pCall [1]; #endif     switch (pCall [3])     {         case 0x20:  // Так вызывается функция с индексом 0                     *pIndex = 0; break;          case 0x60:  // Так вызывается функция с индексами 1...31                     *pIndex = pCall [4] >> 2; break;          case 0xA0:  // Так вызывается функция с индексом 32 и более                     *pIndex = (*(unsigned int*)& pCall [4]) >> 2; break;         default:    // Неизвестный способ. В том числе невиртуальная функция                     return false;     }     return true; }
  Для получения индекса функции вызов функции производится следующим образом:     GetFunctionIndex (& nIndex, &ITest::F);
  Если имя функции перегружено, то лучше завести указатель на функцию     // Наиболее корректный вариант     void (ITest:: * pFunc) (int) = &ITest:: F;     GetFunctionIndex (& nIndex, pFunc);
  Использовать явное преобразование типа крайне нерекомендуется, так как в этом случае можно получить индекс функции, которой на самом деле нет в интерфейсе.     GetFunctionIndex (& nIndex, (void (ITest:: *) ()) &ITest::F);     GetFunctionIndex (& nIndex, (void (ITest:: *) const ()) &ITest::F);     GetFunctionIndex (& nIndex, (void (ITest:: *) (int)) &ITest::F);
   
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Чего-бы ты ни сделал, ты всегда чего-нибудь не сделал... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							mag
							
								Интересующийся 
								
								 
								  Offline
								Пол:   
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #39 : 23-11-2010 07:20 »   | 
								
								 | 
							  
							 
							Антон (LogRus),  а можешь указать то, что печатается у тебя в терминал? В релизной и дебагерной версии? Дело в том, что как я уже отмечал ранее &I::a есть не указатель на функцию void I::a() (кстати это должен быть 0!!!), а указатель на функцию, которая готовит аргументы и затем вызывает виртуальную функцию из таблицы с прописанным в таблице индексом. У меня в VS 2008 это выглядит так (я печатал по формату %p): Debug: 4 ::a=01043D02 I::b=01043D3E I::c=01045DA5 ::a=01043D02 A::b=01043D3E A::c=01045DA5 Release: 4 I::a=00EB1D30 I::b=00EB1D50 I::c=00EB1D70 A::a=00EB1D30 A::b=00EB1D50 A::c=00EB1D70 Боюсь, что разумным образом интерпретировать и преобразовать это я не смогу. >> у меня 64-х битная платформа и GCC, поэтому указатели 64 бита и соотвествующий им printf. Возможно, что в 64-x GCC по данному указателю (или первым его байтам) хранится именно сдвиг в виртуальной таблице >> не сложными вычислениями получаем номер метода n = (aa - 1)/sizeof(aa), отсчёт от нуля Тогда там не нужно вычитать 1, так как нулевой функцией должна быть void a (int); Кстати, насколько я могу судить, в твоем примере класс A совершенно не нужен. Ты не создаёшь объекты данного класса. Впрочем не видя результатов логов я могу ошибаться. А ещё мне бы хотелось увидеть твой лог для двух классов I1 и I2. Именно в таком виде без наследования. Классы A1  и A2 не нужны class I1 { public:     virtual void a() = 0;     virtual void b() = 0;     virtual void c() = 0; }; class I2 { public:     virtual void a() = 0;     virtual void b() = 0;     virtual void c() = 0;     virtual void a(int) = 0; };
 
  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Чего-бы ты ни сделал, ты всегда чего-нибудь не сделал... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #40 : 23-11-2010 07:53 »   | 
								
								 | 
							  
							 
							Offtopic: 
  >>текст содержал операторы типа *++++++++f и *o ^= *o, которые являясь совершенно законными с точки зрения языка (и возможно  >>более эффективные с точки зрения быстродействия) понятны далеко не всякому программисту.
  эффективности они не добавляют - а вот понтов и трудночитаемости да. Одна из причин моей реакции, кстати. Так как это признак гоблинства
  например, *o ^= *o, легко заменяется на *o=0; а *++++++++f  на 
  f+=4; *f
  да и вообще, f лучше сделать типом void*
 
 Поставлю в угол.  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
									« Последнее редактирование: 23-11-2010 07:55 от Алексей1153++ »
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #41 : 23-11-2010 09:29 »   | 
								
								 | 
							  
							 
							Антон (LogRus),  а можешь указать то, что печатается у тебя в терминал? В релизной и дебагерной версии? Дело в том, что как я уже отмечал ранее &I::a есть не указатель на функцию void I::a() (кстати это должен быть 0!!!), а указатель на функцию, которая готовит аргументы и затем вызывает виртуальную функцию из таблицы с прописанным в таблице индексом.
  I1::a=1 I1::b=5 I1::c=9 I2::a=1 I2::b=5 I2::c=9 I2::a(int)=13
  Как видишь реализация, очень специфична для платформы  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							mag
							
								Интересующийся 
								
								 
								  Offline
								Пол:   
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #42 : 23-11-2010 14:09 »   | 
								
								 | 
							  
							 
							Антон (LogRus), да уж... Впрочем, я высказывал изрядную долю скепсиса при использовании таких указателей и в моём (vydtdrt) варианте.
  >> Как видишь реализация, очень специфична для платформы Меня радует только то, что и в 6-й студии всё так же как 2008. Глядишь и впредь ничего ломать не станут. Можно тебя ещё попросить посмотреть в дебагере на саму виртуальную таблицу класса I2 (точнее придётся реализовать производный A2 чтобы создать экземпляр)? А то получается что для перегруженного имени 'a' функция a(int) располагается в конце списка, а не перед функцией a(). 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Чего-бы ты ни сделал, ты всегда чего-нибудь не сделал... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						| 
							Антон (LogRus)
							
						 | 
						
							
								  | 
								
									
									 « Ответ #43 : 23-11-2010 15:28 »   | 
								
								 | 
							  
							 
							сделал пару попыток поглядеть на табличку, её что-то не видно в моём IDE, а другого нет. 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							Странно всё это.... 
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							vydtdrt
							
								Новенький 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #44 : 02-12-2010 07:30 »   | 
								
								 | 
							  
							 
							#include <stdio.h> #include <stdarg.h> #include <psapi.h>
  #include <stdio.h> #include <iostream> #include <dbghelp.h>
  #include <ntdll.h>
  #pragma comment(lib, "psapi") #pragma comment(lib, "shlwapi") #pragma comment(lib, "dbghelp")
  #define crash_if_fail(expr) \ 	do{ \ 	    if (!(expr)) \ 		    DebugBreak(); \ 	} while (0)
  #define return_val_if_fail(expr, val) \ 	do{ \ 	    if (!(expr)) \ 		    return val; \ 	} while (0)
  bool is_stack(void *p){ 	PTEB teb = NtCurrentTeb(); 	void *base = teb->Tib.StackBase; 	void *limit = teb->Tib.StackLimit; 	crash_if_fail(limit && base); 	if (p >= limit && p <= base) 		return true; 	return false; }
  bool is_code_segment__(void *p){ 	char buff[MAX_PATH]; 	char *base; 	DWORD r = GetMappedFileName(GetCurrentProcess(), (HMODULE)p, buff, _countof(buff)); 	return_val_if_fail(r, false); 	char *name = PathFindFileName(buff); 	return_val_if_fail(name != buff, false); 	base = (char*)GetModuleHandle(name); 	return_val_if_fail(base, false);     PIMAGE_NT_HEADERS pim; 	pim = ImageNtHeader(base); 	return_val_if_fail(pim, false); 	PIMAGE_SECTION_HEADER psh = (PIMAGE_SECTION_HEADER)(&pim->OptionalHeader + 1); 	for (int jj = 0; jj < pim->FileHeader.NumberOfSections; jj++){ 		char *q = base + pim->OptionalHeader.AddressOfEntryPoint; 		bool t = q >= base + psh->VirtualAddress && 			q <= base + psh->VirtualAddress + psh->Misc.VirtualSize; 		if (t){ 			t = p >= base + psh->VirtualAddress && 				p <= base + psh->VirtualAddress + psh->Misc.VirtualSize; 			return_val_if_fail(!t, true); 		} 		psh++; 	} 	return false; }
  bool is_correct_prologue(void *p){ 	return !!"dummy"; }
  class r{ 	r(const r&); 	r& operator=(const r&); public: 	r(){} 	template<class t> 	r& operator,(t *v){ 		return this->operator<<(*v); 	} 	template<class t> 	r& operator<<(t &o){ 		crash_if_fail(dynamic_cast<const void*>(&o)); 		int l = 0; 		int n = 0, n_ = sizeof(o) / sizeof(void*); 		while (n < n_){ 			void **a = *((void***)&o + n++); 			if (IsBadReadPtr(a, sizeof(void*)) || is_stack(a)){ 				continue; 			} 			int c = 0; 			void *d = a[c]; 			while (is_code_segment__(d)){ 				print_info(&l, o, n, d, c, a); 				d = a[++c]; 			} 		} 		return *this; 	} 	template<class t> 	void print_info(int *l, const t &o, int n, void *d, int c, void **a){ 		if (!*l){ 			puts("///////////////////////////////////////////////////"); 			printf("object address %p\n", &o); 			*l = 1; 		} 		if (!c){ 			puts("-=-=-=-=-=-=-=-=-=-"); 			printf("%15.1s%p:__vfptr %p\n", "+", ((char*)((void***)&o + n - 1)) - (char*)&o, a); 		} 		printf("%32.p\n", d); 	} };
  class a{ public: 	virtual void f(){} 	virtual ~a(){} }; class b:public a{ public: 	virtual void f(){} 	virtual ~b(){} };
  int main(){ 	a ao; 	b bo; 	r()<<ao<<bo; }
  /////////////////////////////////////////////////// object address 0013FF54 -=-=-=-=-=-=-=-=-=-               +00000000:__vfptr 0041780C                         0041104B                         004110B9 /////////////////////////////////////////////////// object address 0013FF48 -=-=-=-=-=-=-=-=-=-               +00000000:__vfptr 0041781C                         00411046                         0041122B Для продолжения нажмите любую клавишу . . .  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							Алексей++
							
								глобальный и пушистый 
								Глобальный модератор
								
								 
								  Offline
								
								Сообщений: 13
								
								
								
								
								
							  
						 | 
						
							
								  | 
								
									
									 « Ответ #45 : 02-12-2010 08:38 »   | 
								
								 | 
							  
							 
							vydtdrt, извиняюсь за неправильный бан. Но ты сам в чём-то виноват - ник корявый, по человечьи не говоришь, код страшный 
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							
						 | 
					 
				 
			 |  
		 
	 | 
	
		
		
			
				
					
						
							sss
							
								Специалист 
								
								 
								  Offline
								
								
								
								
							 
						 | 
						
							
								  | 
								
									
									 « Ответ #46 : 03-12-2010 06:26 »   | 
								
								 | 
							  
							 
							Интересно... Узкое место - если у исходного объекта есть структуры не кратные ( и не выравненные) размеру указателя... А так в принципе норм..  
  
						 | 
					 
					
						
							
								| 
								 | 
							 
								| 
								 | 
								
									 
									Записан
								 | 
							  
							 
							 while (8==8)  
						 | 
					 
				 
			 |  
		 
	 | 
	 |