Se stie ca functia sizeof reuseste sa returneze dimensiunea oricat de complicata ar arata expresia ce ii este trimisa ca argument. Defapt nici nu evalueaza expresia, sa zicem ca pur si simplu foloseste tipul atasat expresiei. De aici putem conchide ca si compilatorul stie cate ceva si despre relatiile de mostenire dintre obiecte.
Vom scrie o clasa template, ce primeste cele doua tipuri de date si decide daca exista o relatie de legatura intre cele doua. Mai exact returneaza existenta relatiei U->T.
template<class T, class U>
struct Conversion
{
typedef char size1;
typedef struct {
char dummy[2];
}size2;
static T TType;
static size1 Test(U);
static size2 Test(...);
public:
enum{exists = sizeof(Test(TType)) == sizeof(size1), sametype = false};
};
Clasa declara doua tipuri care sa fie in mod evident diferite ca dimensiune: size1 si size2. Pe langa aceastea, clasa mai vine si cu doua functii Test: una generica ce foloseste puncte de suspensie si returneaza dimensiunea size2 si una explicita ce returneaza dimensiunea size1. Definitiile lor nu sunt necesare fiindca am zis ca functia sizeof " arunca" expresia si returneaza doar tipul. Acuma, daca tipul T este cu adevarat derivat din tipul U, compilatorul va folosi cea mai calificata functie Test, adica functia Test(U) intrucat compilatorul "stie" ca se poate face downcast de la tipul T la tipul U. Variabila exists se va dezvolta in sizeof(Test(U)) == sizeof(size1) care este un adevar evident.Pe langa asta va trebui sa ne asiguram si ca cele doua tipuri nu sunt identice pentru a putea vorbi de mostenire. Vom face o calificare partiala a clasei pentru situatia asta.
template<class T>
struct Conversion<T,T>
{
enum{exists = 1, sametype = 1};
};
Iata si testul final:
struct A
{
int dummy1;
};
struct B:public A
{
int dummy2[3];
};
bool inheritance = Conversion<B,A>::exists && !Conversion<B,A>::sametype; // TRUE
inheritance = Conversion<B,size_t>::exists && !Conversion<B,A>::sametype; // FALSE
Niciun comentariu:
Trimiteți un comentariu