【问题标题】:How do I check if a variable derives from a class?如何检查变量是否派生自类?
【发布时间】:2019-06-06 09:03:47
【问题描述】:

我想打印多种类型的变量。我创建了一个名为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 &lt;&lt; p.ToString() &lt;&lt; std::endl; 解决了这个问题,但我想知道是否有更好的解决方案。

【问题讨论】:

  • 简单的void PrintVariable(const IStringable&amp; var) {} 会做你所期望的。如果你试图将不是从IStringable 派生的东西传递给这个函数,编译器会阻止你这样做。
  • 您希望PrintVariable 也可以使用不是从IStringable 派生的实例来调用吗?在这种情况下该函数应该做什么?
  • 是的。如果PrintVariable 被调用,例如int 它应该在该 int 上使用 std::string() 以便将其转换为 std::string 以便它可以在 std::cout 中使用
  • 我不敢写这个作为答案,但我认为你的方法存在根本缺陷。请求每个类型从IStringable 继承是相当侵入性的,并不是真正需要的。您通常为operator&lt;&lt; 提供重载以便能够打印某些内容。另一方面,如果您想保留该界面,那么我仍然会选择operator&lt;&lt;,它可以调用相应的ToString,而不是您的PrintVariable

标签: c++ inheritance


【解决方案1】:

您不需要模板:

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

只有对象可转换为IStringablePrintVariable 调用是合法的:

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();
}

所以你可以写:

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

从 cmets 看来,OP 想要一种记录事物的方法。一个最小的实现是:

#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));
    }
}

这个想法是使用ADLSFINAE 调用std::to_stringISrtingable::ToString 来记录事物,并记录结果字符串。

用法:

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

int main()
{
    Person p("Alice");
    double d = 0.0;
    const char* c = "Some words";

    Logger::log(p);
    Logger::log(d);
    Logger::log(c);
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 2021-10-07
    相关资源
    最近更新 更多