如何检查变量是否派生自类?
How do I check if a variable derives from a class?
我想打印多种类型的变量。我创建了一个名为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;
来解决此问题,但我想知道是否有更好的解决方案。
你不需要模板:
void PrintVariable(const IStringable& var) {
std::cout << var.ToString() << 'n';
}
只有使用可转换为IStringable
的对象调用PrintVariable
才是合法的:
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';
从评论中可以看出,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));
}
}
这个想法是使用 ADL 和 SFINAE 调用要记录的事物上的std::to_string
或ISrtingable::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
相关文章:
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 是否可以为 QPixmap 派生类嵌入缩放方法?
- 检查一个类型是否直接派生自"enable if"上下文中的另一个类型(是其子类型)
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- 是否可以使用 using 将基类中的公共成员重新声明为派生类中的私有成员?
- 将基本实例指针强制转换为派生实例指针是否合法?(实例不是派生实例)
- 从模板基类派生是否在派生类声明的点实例化模板
- 是否可以将CRTP与本身已模板化的派生类一起使用
- C++多态性:如何测试一个类是否派生自另一个基类
- 如果所有派生类在编译时都是已知的,那么final关键字是否提供了优化
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- 派生类是单例是否是一种好的做法
- C++ 多态性:如果派生类中的虚函数在基类中声明了常量,是否需要将其声明为常量
- 是否可以从派生类返回基类的实例?
- 基类对象是否隐式添加到派生类中?
- 从不可复制派生 AbstractBaseClasses (ABC) 是否有缺点?
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 是否可以在引用另一个派生类的派生类中声明复制构造函数?
- 继承函数是否适用于 C++ 中的基类元素或派生类元素?
- 如果我只使用指向基类的指针,更改私有派生类是否会影响 ABI?