C++ проверка на типа по време на компилация

всичко. Аз съм доста нов в C++ и пиша малка библиотека (най-вече за моите собствени проекти) в C++. В процеса на проектиране на йерархия на типове се натъкнах на проблема с дефинирането на оператора за присвояване.

Възприех основния подход, който в крайна сметка беше постигнат в тази статия , което е, че за всеки клас MyClass в йерархия, получена от клас Base, вие дефинирате два оператора за присвояване така:

class MyClass: public Base {
public:
    MyClass& operator =(MyClass const& rhs);
    virtual MyClass& operator =(Base const& rhs);
};

// automatically gets defined, so we make it call the virtual function below
MyClass& MyClass::operator =(MyClass const& rhs);
{
    return (*this = static_cast<Base const&>(rhs));
}

MyClass& MyClass::operator =(Base const& rhs);
{
    assert(typeid(rhs) == typeid(*this)); // assigning to different types is a logical error
    MyClass const& casted_rhs = dynamic_cast<MyClass const&>(rhs);
    try {
        // allocate new variables
        Base::operator =(rhs);
    } catch(...) {
        // delete the allocated variables
        throw;
    }
    // assign to member variables
}

Частта, която ме интересува, е твърдението за равенство на типове. Тъй като пиша библиотека, където твърденията вероятно ще бъдат компилирани от крайния резултат, това ме накара да използвам схема, която изглежда по-скоро така:

class MyClass: public Base {
public:
    operator =(MyClass const& rhs); // etc
    virtual inline MyClass& operator =(Base const& rhs)
    {
        assert(typeid(rhs) == typeid(*this));
        return this->set(static_cast<Base const&>(rhs));
    }
private:
    MyClass& set(Base const& rhs); // same basic thing
};

Но се чудех дали мога да проверя типовете по време на компилация. Разгледах Boost.TypeTraits и се доближих, като направих BOOST_MPL_ASSERT((boost::is_same<BOOST_TYPEOF(*this), BOOST_TYPEOF(rhs)>));, но тъй като rhs е деклариран като препратка към родителския клас, а не към производния клас, той се задави.

Сега като се замисля, разсъжденията ми изглеждат глупави -- надявах се, че тъй като функцията е вградена, тя ще може да проверява самите действителни параметри, но разбира се препроцесорът винаги се изпълнява преди компилатора. Но се чудех дали някой знае за друг начин, по който мога да наложа този вид проверка по време на компилация.


person Masterofpsi    schedule 12.04.2010    source източник
comment
Няма начин да се проверят типовете по време на компилиране, защото това е целият смисъл на полиморфизма: типът на нещата се определя само по време на изпълнение. Animal* animal = rand() % 2 ? new Dog() : new Cat();   -  person UncleBens    schedule 12.04.2010
comment
Добра статия, свързана между другото, благодаря за това :)   -  person Matthieu M.    schedule 12.04.2010


Отговори (2)


Не можете да изпълните това твърдение по време на компилиране по простата причина, че типовете по време на изпълнение няма да бъдат известни, докато, добре, времето на изпълнение.

assert(typeid(rhs) == typeid(*this));
return this->set(static_cast<Base const&>(rhs));

В невградената версия имахте dynamic_cast. Бих запазил това, за да получите добре дефинирана грешка, а не недефинирано поведение, ако вашето твърдение е нарушено.

Ако направите това, твърдението е или прекалено ограничително, или безсмислено. dynamic_cast ще хвърли bad_cast изключение както в компилациите за отстраняване на грешки, така и при издаването. Това е, което искате.

Лично аз бих поставил под въпрос целия проблем с полиморфното присвояване. Бих следвал съвета на Скот Майерс за Ефективен C++ и бих направил всички ваши нелистови възли в йерархията на наследяване абстрактни. След това можете да направите операторите за присвояване на базов клас защитени и невиртуални.

Това ви позволява да използвате тяхната реализация в оператор за присвояване на производни класове, но не позволява на клиентите да нарязват обекти. Ако клиентски клас има само препратка към базов клас или указател, е под въпрос дали трябва да се опитва да присвои към класа така или иначе. Ако е така, те трябва да носят отговорност за гаранциите за безопасност на отливките и типа.

person CB Bailey    schedule 12.04.2010
comment
+1 за protected оператор за присвояване и конструктор за копиране за нелистови класове. Така или иначе винаги има виртуален clone метод за копиране. - person Matthieu M.; 12.04.2010

Ако искате нещата да се определят по време на компилиране, тогава динамичният полиморфизъм (виртуални функции и т.н.) не е правилният инструмент за вас. Като цяло не виждам необходимостта да смесвам динамичен полиморфизъм с неща, които имат "нормалните типове стойност" -- като оператори за присвояване. Може би конкретните и неполиморфните класове са това, което работи най-добре във вашия случай. Но е трудно да се каже, защото не си казал нищо за това, което се опитваш да направиш с класовете.

person sellibitze    schedule 12.04.2010