如何检查变量是否从类派生?

时间:2019-06-06 09:03:47

标签: c++ inheritance

我想打印许多类型的变量。我已经创建了一个名为IStringable的类,并且派生了一些类。在我的PrintVariable函数中,我想检查参数是否源自IStringable,如果确实要打印该参数。

class IStringable {
public:
    virtual ~IStringable() { }
    virtual std::string ToString() const = 0;
}

class Person : public IStringable {
public:
    Person(const std::string name) : _name(name) { }
    virtual std::string ToString() const { return _name; }
private:
    std::string _name;
}

// This does not work as intended, as I don't know how it could be implemented
template <>
void PrintVariable<IStringable>(const IStringable& var) {
    std::cout << var.ToString() << std::endl;
}

int main() {
    Person p("Foo");
    PrintVariable(p);
}

到目前为止,我只是通过使用std::cout << p.ToString() << std::endl;来解决此问题,但我想知道是否有更好的解决方案。

1 个答案:

答案 0 :(得分:8)

您不需要模板:

void PrintVariable(const IStringable& var) {
    std::cout << var.ToString() << '\n';
}

仅调用对象可转换为PrintVariable的{​​{1}}是合法的:

IStringable

此外,您可以将Person p("Alice"); struct Bob {} b; PrintVariable(p); // OK PrintVariable(b); // ill-formed: no conversion from Bob to const IStringable& 重新设计为运算符:

PrintVariable

所以你可以这样写:

std::ostream& operator<<(std::ostream& os, IStringable const& rhs)
{
    return os << rhs.ToString();
}

从评论中可以看出,OP希望记录事件。最小的实现是:

Person p("Alice");
std::cout << p << '\n';

想法是使用ADLSFINAE在要记录的事物上调用#include <string_view> #include <type_traits> #include <iostream> namespace Logger { struct IStringable { virtual ~IStringable() {} virtual std::string ToString() const = 0; }; std::string to_string(IStringable const& v) { return v.ToString(); } void log(std::string_view const& sv) { std::cout << "debug: " << sv << '\n'; } template<class T, std::enable_if_t<!std::is_convertible_v<T, std::string_view>, int> = 0> void log(T const& v) { using std::to_string; log(to_string(v)); } } std::to_string,并记录生成的字符串。

用法:

ISrtingable::ToString

演示:https://coliru.stacked-crooked.com/a/77e19e87c9d4780d