Что должно использоваться для проверки идентификационных данных в C++?

Microsoft имеет API все о сканировании. Это звонило Приобретение Windows Image , и можно прочитать большую статью Coding4Fun об этом никем другим, чем Scott Hanselman здесь .

5
задан Peter Mortensen 19 October 2009 в 21:04
поделиться

9 ответов

Если ваши классы действительно точно такие, как указано, это невозможно, поскольку во время выполнения недостаточно информации для восстановления необходимой информации.

Если они действительно полиморфные классы с виртуальными функциями, похоже, что dynamic_cast - это ответ. Он возвращает указатель на самый производный объект. Тогда ваш чек будет dynamic_cast (a) == dynamic_cast (b) .

См. Пункт 7 здесь:

http: //www.csci.csusb .edu / dick / c ++ std / cd2 / expr.html # expr.dynamic.cast

Я подозреваю, что применяются обычные dynamic_cast проблемы, т. е. нет гарантии, что это будет быстро, и ваш классы должны быть полиморфными.

Это не та функция, которую я использовал сам, я '

8
ответ дан 13 December 2019 в 05:38
поделиться

Есть простой и трудный путь.

Простой способ - ввести пустой виртуальный базовый класс. Каждый объект, унаследованный от такого класса, получает указатель на общую точку в «реальном» объекте, чего вы и хотите. У указателя есть небольшие накладные расходы, но нет никаких ветвей или чего-то еще.

class V {};
class B1 : public virtual V {}; // sizeof(B1) = sizeof(void*)
class B2 : public virtual V {}; // sizeof(B2) = sizeof(void*)
class D : public B1, public B2 {}; // sizeof(D) = 2*sizeof(void*)

bool same( V const *l, V const *r ) { return l == r; }

Сложный путь - попытаться использовать шаблоны. Здесь уже есть несколько приемов ... при взломе с использованием шаблонов помните, что вы, по сути, заново изобретаете часть языка, только с надеждой на меньшие накладные расходы за счет управления информацией о времени компиляции. Можем ли мы снизить накладные расходы на виртуальный базовый класс и исключить этот указатель? Это зависит от того, насколько универсальность вам нужна. Если ваши базовые классы могут быть организованы в производном объекте несколькими способами, то, безусловно, есть информация, которую вы можете '

3
ответ дан 13 December 2019 в 05:38
поделиться

Нет общего способа сделать это. Подобъекты базового класса, как правило, не знают, что они есть, поэтому, если у вас есть только указатель на подобъект базового класса, у вас нет никаких средств для получения указателя на самый производный объект, которому он принадлежит, если вы не знаю заранее, какой тип последнего.

Начнем с этого:

 struct B1 { char b1; };
 struct B2 { char b2; };
 struct D : B1, B2 { char d; };

 // and some other type...
 struct Z : B2, B1 { };

Рассмотрим типичную реализацию макета в памяти D . В отсутствие vtable единственное, что у нас есть, это необработанные данные (и, возможно, заполнение):

       Offset    Field
       ------    -----
    /       0    b1     >- B1
 D-<        1    b2     >- B2
    \       2    d  

У вас есть два указателя:

B1* p1;
B2* p2;

Каждый указатель фактически указывает на один char в экземпляре D . Однако, если вы не знаете этого заранее, как вы можете сказать? Там' s также возможность того, что указатели могут скорее указывать на подобъекты в экземпляре Z , и, глядя на сами значения указателей, явно нет способа сказать; и нет ничего, что вы (или компилятор) могли бы вывести из данных, на которые ссылается указатель, поскольку это всего лишь один байт данных в структуре.

3
ответ дан 13 December 2019 в 05:38
поделиться

За исключением интеллектуальных указателей (которые на самом деле не указатели, а объекты класса), перегрузка operator == для указателей невозможна, поэтому приведение не должно быть необходимым.

Конечно, сравнение указателей разных типов может не работать. Как вы думаете, зачем вам это нужно?

1
ответ дан 13 December 2019 в 05:38
поделиться

Итак, вы ищете решение во время компиляции. Я не верю, что это возможно, как указано в C ++. Вот мысленный эксперимент:

Файл Bases.hpp:

class B1 {int val1;};
class B2 {int val2;};

Файл Derived.hpp:

#include <Bases.hpp>
class D : public B1, public B2 {};

Файл Composite.hpp:

#include <Bases.hpp>
class C
{
   B1 b1;
   B2 b2;
};

Файл RandomReturn.cpp:

#include <Composite.hpp>
#include <Derived.hpp>
#include <cstdlib>

static D derived;
static C composite;

void random_return(B1*& left, B2*& right)
{
    if (std::rand() % 2 == 0)
    {
        left=static_cast<B1*>(&derived);
        right=static_cast<B2*>(&derived);
    }
    else
    {
        left=&composite.b1;
        right=&composite.b2;
    }
}

Теперь предположим, что у вас есть:

#include <Bases.hpp>
#include <iostream>

extern void random_return(B1*& , B2*& );

// some conception of "is_same_object"    
template <...> bool is_same_object(...) ...

int main()
{
    B1 *left;
    B2 *right;

    random_return(left,right);
    std::cout<<is_the_same_object(left,right)<<std::endl;
}

Как могли бы мы реализовать здесь is_same_object здесь, во время компиляции, ничего не зная о классе C и классе D ?

С другой стороны, если вы ' Если вы хотите изменить гипотезу, она должна быть работоспособной:

class base_of_everything {};
class B1 : public virtual base_of_everything {};
class B2 : public virtual base_of_everything {};

class D : public B1, public B2, public virtual base_of_everything {};

...
// check for same object
D d;
B1 *b1=static_cast<B1*>(&d);
B2 *b2=static_cast<B2*>(&d);

if (static_cast<base_of_everything*>(b1)==static_cast<base_of_everything*>(b2))
{
    ...
}
0
ответ дан 13 December 2019 в 05:38
поделиться

Используйте boost :: addressof . Я думаю, это лучший способ. boost :: addressof предоставляется для получения адреса в любом случае, независимо от потенциального использования или неправильного использования перегрузки оператора. Используя некий умный внутренний механизм, шаблонная функция addressof гарантирует, что он достигнет фактического объекта и его адреса. Взгляните на это

#include "boost/utility.hpp"

class some_class {};

int main() {
  some_class s;
  some_class* p=boost::addressof(s);
}
0
ответ дан 13 December 2019 в 05:38
поделиться

If you need to compare the identity of your objects, why wouldn't you give them one? After all, it's you who decides what makes the identity of the object. Let the compiler do it, and you're bound to the compiler's limitations.

Something in the way of...

class identifiable {
    public:
    long long const /*or whatever type*/ identity;
    static long long sf_lFreeId() { 
       static long long lFreeId = 0;
       return lFreeId++; // not typesafe, yet
    }
    identifiable(): identity( sf_lFreeId() ) {}
    bool identical( const identifiable& other ) const { 
      return identity == other. identity;
    }
};

class A : public identifiable {
};

....

A a1, a2;
A& a3 = a1;

assert( !a1.identical(a2) );
assert( a1.identical( a3 ) );
0
ответ дан 13 December 2019 в 05:38
поделиться

Вы можете проверить, чтобы указать, перекрываются ли объекты в памяти (взято из ответа Марка Рэнсома). Это вызывает неопределенное поведение, но должно делать то, что вы хотите, на любом подходящем компиляторе:

template <typename T1, typename T2>
bool is(const T1 *left, const T2 * right)
{
    const char *left_begin=reinterpret_cast<const char*>(left);
    const char *left_end=left_begin+sizeof(*left);

    const char *right_begin=reinterpret_cast<const char*>(right);
    const char *right_end=right_begin+sizeof(*right);

    return ( left_begin  <= right_begin && right_begin < left_end) ||
           ( right_begin <= left_begin  && left_begin < right_end);
}
-2
ответ дан 13 December 2019 в 05:38
поделиться

Ваш подход работал у меня даже в указанном вами случае:

class B1 {};
class B2 {};
class C : public B1, public B2 {};

int main() {
  C c;
  B1 *a = &c;
  B2 *b = &c;

 if ((void*)a == (void*)b) {
  printf("equal");
 }
 else {
  printf("not equal!");
 }

}

печатает здесь «равно» ..

-1
ответ дан 13 December 2019 в 05:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: