Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I check if a variable derives from a class?

I want to print variables of many types. I've made a class named IStringable, and some classes that derive from it. In my PrintVariable function I want to check whether the parameter derives from IStringable, and if it does then print it.

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

So far I've worked around this problem by just using std::cout << p.ToString() << std::endl; instead, but I'm wondering if there's a better solution to this.

like image 641
Guy Simonsen Avatar asked Jun 06 '19 09:06

Guy Simonsen


People also ask

How do you check if an object belongs to a certain class in Python?

The isinstance() function checks if the object (first argument) is an instance or subclass of the class info class (second argument).

How do you find the variable inside a class?

Use class_name dot variable_name to access a class variable from a class method in Python. Use instance to access variables outside the class.

How do I check if an object is an instance of a given class or of a subclass of it?

isinstance() checks whether or not the object is an instance or subclass of the classinfo.

How do you check if an object is of a certain class C++?

C++ has no direct method to check one object is an instance of some class type or not. In Java, we can get this kind of facility. In C++11, we can find one item called is_base_of<Base, T>. This will check if the given class is a base of the given object or not.


1 Answers

You don't need a template:

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

Only calls to PrintVariable with object convertible to IStringable are legal:

Person p("Alice");
struct Bob {} b;
PrintVariable(p); // OK
PrintVariable(b); // ill-formed: no conversion from Bob to const IStringable&

Additionally, you could redesign PrintVariable as an operator:

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

So you could write:

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

As it appears from comments, OP whants a way to log things. A minimal implementation would be:

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

The idea is to use ADL and SFINAE to call either std::to_string or ISrtingable::ToString on the thing to log, and log the resultant string.

Usage:

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

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

like image 114
YSC Avatar answered Oct 25 '22 09:10

YSC