Adresa metody ze třídního ukazatele – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Adresa metody ze třídního ukazatele – C / C++ – Fórum – Programujte.comAdresa metody ze třídního ukazatele – C / C++ – Fórum – Programujte.com

 

Kureal
~ Anonymní uživatel
4 příspěvky
10. 4. 2011   #1
-
0
-

Dobrý den,
je možné získat adresu metody ze třídního ukazatele? Tedy něco na tento způsob:

class A

{
public:
void Method();
}

unsigned long GetMethodAddress(A* ptrA, void (A::*ptrMethodInA)())
{
//return reinterpret_cast<unsigned long>(ptrA->*ptrMethodInA);
return ???;
}

A Obj;
cout << "Adresa metody: " << GetMethodAddress(&Obj, &Obj::Method) << endl;


Abych byl konkrétní. Potřebuju vygenerovat ID metod, kde se jejich ukazatel (shared_ptr) ukládá do kontejneru MAP. No a tyto metody pak potřebuji podle tohoto ID volat, odebírat z kontejneru a tak podobně. No a přišlo mi rozumné pro toto ID použít jejich adresu, když už mám ten ukazatel.

Díky moc za rady!
Kureal

Nahlásit jako SPAM
IP: 85.71.92.–
ondra.holub+1
Stálý člen
10. 4. 2011   #2
-
0
-

Ukazatel na metodu je jiný ukazatel než běžný ukazatel. Na některých překladačích zabírá dokonce i více místa. K jeho použití je potřeba instance třídy (ať už ve formě reference nebo ukazatele na třídu). Bez té konkrétní instance s ním nelze dělat nic jiného než přiřazovat a případně možná porovnávat.

Dost dobře nechápu ten příklad. Funkce GetMethodAddress dostane dva parametry - ukazatel na instanci a ukazatel na metodu. A udělá z toho unsigned long. To není zrovna moc typově bezpečné.

Pokud jde o to, někde si uložit "něco", co lze později zavolat - tedy nějaký funktor - tak není problém si obojí zabalit do nějaké třídy:

struct ftor

{
ftor(A* ptrA, void (A::*ptrMethodInA)())
: ptrA_(ptrA),
ptrMethodInA_(ptrMethodInA)
{
}

void operator()()
{
(ptrA_->*ptrMethodInA)();
}

A* ptrA_;
void (A::*ptrMethodInA_)();

}; // struct ftor

Nahlásit jako SPAM
IP: 212.96.189.–
Kureal
~ Anonymní uživatel
4 příspěvky
10. 4. 2011   #3
-
0
-

Díky za odpověď.
Instanci k tomu třídnímu ukazateli mám - ve formě ukazatele. Ale vlastně mi nejde o to jak takovouto funkci zavolat, ale jak získat její adresu. Nebo ještě lépe - dostanu ukazatel na instanci třídy a třídní ukazatel a potřebuji získat nějaký jedinečný identifikátor této funkce. Tedy nějaké nejlépe číslo, které bude pro každou takto předanou metodu jedinečné a zároveň při dalších předáních stejné metody stejné. Takže mi nejde ani o tu typovou bezpečnost, potřebuji jen jakýsi "otisk".

Nevím jestli se mi to podařilo popsat dostatečně a srozumitelně.

Nahlásit jako SPAM
IP: 85.71.92.–
ondra.holub+1
Stálý člen
10. 4. 2011   #4
-
0
-

No pokud jde jenom o jedinečnost metody, tak ta instance ani není potřeba. Stačí něco takového:

class Method

{
public:
template<typename C, typename T>
static unsigned long Id(T (C::*)())
{
static const id = counter_++;
return id;
}

// A pak zopakovat pro metody s jedním parametrem, se dvěma...
template<typename C, typename T, typename P1>
static unsigned long Id(T (C::*)(P1))
{
static const id = counter_++;
return id;
}

template<typename C, typename T, typename P1, typename P2>
static unsigned long Id(T (C::*)(P1, P2))
{
static const id = counter_++;
return id;
}

private:
static unsigned long counter_;

}; // class Method

unsigned long Method::counter_ = 0;

// Pak se to použije takto:
unsigned long id1 = Method::Id(&MyClass::method1);
unsigned long id1 = Method::Id(&MyClass2::method2);
Pokud ten identifikátor má být různý i pro stejné metody různých instancí téže třídy, tak by se musela ta metoda id upravit třeba nějak takto:
    template<typename C, typename T>

static unsigned long Id(C* c, T (C::*)())
{
static std::map<C*, unsigned long> m;

const std::map<C*, unsigned long>::const_iterator it = m.find(c);
if (it != m.end())
return it->second;

return m.insert(std::make_pair(c, counter_++)).first->second;
}
Je zde samozřejmě problém, že v případě vytvoření nové instance se stejnou adresou, jakou již měla instance stejného typu, bude vrácená hodnota stejná. To by se dalo řešit odstraňováním těchto hodnot v destruktoru dané třídy, ale to vše už jsou jenom spekulace. Záleží na tom, na co to celé je.

Ale určitě to jde i nějak jinak. Toto je takové rychlé ad-hoc řešení.

Nahlásit jako SPAM
IP: 212.96.189.–
Kureal
~ Anonymní uživatel
4 příspěvky
10. 4. 2011   #5
-
0
-

Opravdu moc díky. Tolik řádků kvůli mě jsem nečekal :-).

Jen to moc neřeší můj problém. Potřebuji především, aby Method::Id(&MyClass::method1); vrátila vždy stejné číslo. Tedy něco v tomto smyslu:

cout << Method::Id(&MyClass::method1) << endl;	//1

cout << Method::Id(&MyClass::method2) << endl; //2
cout << Method::Id(&MyClass2::method1) << endl; //3
cout << Method::Id(&MyClass::method1) << endl; //1
cout << Method::Id(&MyClass2::method1) << endl; //3


Vlastně budu mít třidu se 2-mi metodami:
template<class T> void Handler::RegisterMethod(T* Obj, void (T::* Func));

template<class T> void Handler::UnregisterMethod(T* Obj, void (T::* Func));


A potřebuju, aby když z různých míst budu registrovat různé metody různých tříd, aby to fungovalo nějak následovně:
[seznam]Když se zavolá RegisterMethod, zkontroluje se, jestli je metoda už vložená do std::map, pokud ne, vloží ji (nebude ji vkládat vícekrát).
Když se zavolá UnregisterMethod, mělo by se zkontrolovat, jestli v std::map je a případně ji odstraní.[/seznam]

Takže vlastně to nemusí být žádná věc na principu ID, ale porovnávat existenci metod v std::map podle adresy této metody mi přišlo OK. Ale nevím jestli to vůbec je možné.

Nahlásit jako SPAM
IP: 85.71.92.–
ondra.holub+1
Stálý člen
10. 4. 2011   #6
-
0
-

> Potřebuji především, aby Method::Id(&MyClass::method1); vrátila vždy stejné číslo.

Jo, však ono to vrací stejné číslo. Psal jsem to z hlavy, tak tam bylo pár překlepů, ale zkus toto:

#include <iostream>


class Method
{
public:
template<typename C, typename T>
static unsigned long Id(T (C::*)())
{
static const unsigned long id = counter_++;
return id;
}

// A pak zopakovat pro metody s jedním parametrem, se dvěma...
template<typename C, typename T, typename P1>
static unsigned long Id(T (C::*)(P1))
{
static const unsigned long id = counter_++;
return id;
}

template<typename C, typename T, typename P1, typename P2>
static unsigned long Id(T (C::*)(P1, P2))
{
static const unsigned long id = counter_++;
return id;
}

private:
static unsigned long counter_;

}; // class Method

unsigned long Method::counter_ = 0;

class C1
{
public:
void m1() { }
void m2(int) { }
};

class C2
{
public:
void m3() { }
int m4() { }
double m5(const char*) { }
};

int main()
{
std::cout << Method::Id(&C1::m1) << '\n';
std::cout << Method::Id(&C1::m2) << '\n';
std::cout << Method::Id(&C2::m3) << '\n';
std::cout << Method::Id(&C2::m4) << '\n';
std::cout << Method::Id(&C2::m5) << '\n';

std::cout << "========================\n";

std::cout << Method::Id(&C1::m1) << '\n';
std::cout << Method::Id(&C1::m2) << '\n';
std::cout << Method::Id(&C2::m3) << '\n';
std::cout << Method::Id(&C2::m4) << '\n';
std::cout << Method::Id(&C2::m5) << '\n';
}
Proto je v té metodě Id proměnná id deklarovaná jako static.

Ta mapa by podle mě asi fungovat nemohla, protože ukazatele na různé metody (s různými parametry a různých tříd) nejsou vzájemně kompatibilní, takže by byl problém, jaký zastřešující typ použít.

Výše uvedený kód je trošku ukecaný, protože je třeba uvést šablony pro různé počty parametrů (a to tam nemám const metody, případně nějaké další modifikátory). Bohužel zatím v současné normě nejsou šablony s proměnlivým počtem parametrů, kterými by to šlo řešit. Ale není problém si takový kód vygenerovat nebo použít nějaké opakovací makra (něco je třeba v boostu).

Nahlásit jako SPAM
IP: 212.96.189.–
KIIV
~ Moderátor
+43
God of flame
10. 4. 2011   #7
-
0
-

zatim nechapu na co to potrebujes .. ale pripada mi ze hledas spis "polymorfizmus" .. ale spis zalezi o co kraci

Nahlásit jako SPAM
IP: 94.142.234.–
Program vždy dělá to co naprogramujete, ne to co chcete...
ondra.holub+1
Stálý člen
10. 4. 2011   #8
-
0
-

I když vlastně místo té spousty template metod pro různé počty parametrů by stačila jedna:

    template<typename METHOD>

static unsigned long MId(METHOD)
{
static const unsigned long id = counter_++;
return id;
}
Sice to pak sežere i jakýkoliv jiný typ, ale zase je to o dost kratší.

Nahlásit jako SPAM
IP: 212.96.189.–
Kureal
~ Anonymní uživatel
4 příspěvky
10. 4. 2011   #9
-
0
-

To je bezvadný!
Nevím proč jsem si před tím myslel, že to bude vracet různé hodnoty. Nicméně díky moc. Funguje to skvěle.

Dělal jsem něco na způsob událostí v C# a prakticky jsem to měl - až na tady tento problém. Fungovalo to vždy pro jednu metodu z 1 třídy, protože jsem sice třídu/instanci dokázal rozlišit přes její adresu, ale metodu v rámci třídy už ne.

Takže ještě jednou díky!

Nahlásit jako SPAM
IP: 85.71.92.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 2 hosté

Podobná vlákna

C# ukazatelé — založil Kubas129

C++ Ukazatele — založil pointer

Ukazatele — založil Šimon

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý