производные классы и проверка типов

Я пытаюсь написать метод, который принимает в качестве аргумента класс, производный от std::string. Метод перегружен несколькими различными сигнатурами функций. Я бы хотел, чтобы компиляция потерпела неудачу, если я попытаюсь вызвать ее с помощью std::string или, по крайней мере, с ошибкой времени выполнения, но, видимо, компилятор слишком умен для меня.

class NotAString : public std::string {
    NotAString(std::string str) : std::string(str) { }
};


class Foo {
   Foo();
   void bar(NotAString);
   void bar(int)
};

Это компилируется и запускается

Foo foo();
foo.bar(NotAString("baz"));

Но так же и это:

Foo foo();
foo.bar(std::string("baz"));

Я пробовал использовать typeid(str) вот так:

void Foo::Bar(NotAString str) {
    if(typeid(&str) != typeid(new NotAString()) {
        throw std::bad_typeid();
    }
}

Но он всегда выдает исключение, если передается std::string или NotAString. Я пробовал использовать dynamic_cast так:

void Foo::Bar(NotAString str) {
    if (dynamic_cast<NotAString*>(&str) == NULL) {
        throw std::bad_type();
    }
}

Но он никогда не выдает исключение.

Цель состоит в том, чтобы иметь возможность различать строку и строку, представляющую ключ для поиска ключ-значение. Как я могу изменить свой класс NotAString или применить более строгую проверку типов компилятором, чтобы заставить его работать так, как мне хотелось бы?


person Dan    schedule 28.01.2013    source источник
comment
Получение от std::string - плохая идея.   -  person chris    schedule 28.01.2013
comment
NotAString это std::string. Итак, у вас есть класс, который по своему имени является не строкой, а строкой. Я собираюсь выпить что-нибудь.   -  person Zeta    schedule 28.01.2013


Ответы (2)


Проблема в том, что ваш конструктор NotAString(std::string str) не explicit, поэтому он позволяет неявные преобразования из std::string в NotAString.

Когда вы вызываете функцию с std::string, компилятор замечает, что вы можете вызвать ее путем преобразования аргумента через конструктор, поэтому он создает временный NotAString и передает его функции.

Если вы объявите его explicit NotAString(std::string str), он не допустит этих неявных преобразований.

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

person Jonathan Wakely    schedule 28.01.2013

Плохие дизайнерские идеи в сторону, измените этот конструктор...

class NotAString : public std::string {
    NotAString(std::string str) : std::string(str) { }
};

...to be explicit:

class NotAString : public std::string {
    explicit NotAString(std::string str) : std::string(str) { }
};

Это предотвратит неявное преобразование объектов std::string в NotAString, когда они используются в качестве параметра функции.

person Drew Dormann    schedule 28.01.2013