问题
I'm fairly new to C++, I've been mainly using python. I'm trying to check the type of variable of the value stored in the objects I'm working on. I remember that in Python there was a comand isinstance
where I could use it as a condition to run certain commands, like if the next value is a string, do A, and if it's an int do B.
Is there a way to quickly check what's the data type on a variable in C++?
Example:
In python I had an array with a math operation, each character in a field
[3,"+",2]
as I read the array I would separate the ints from the strings with the isinstance command
if isinstance(list[0],int):
aux1.append(list[0])
list=list[1:]
else:
if isinstance(lista[0],str):
aux2.append(list[0
list=list[1:]
now in C++ I need to do something similar, but this time each character is in a node from a linked list and again, I need to separate them, ints in a linked list, and strings in another linked list
回答1:
What you seem to be struggling with is that C++ is a statically and a (relatively) strongly typed language. For a discussion about what each of these terms actually mean i refer to this other question, as it's explained there probably much better than I could.
First of all you should be sure that you actually need to do things the way you're trying currently. Do not try to write Python style code.
That said, there are basically two different approaches with which you can achieve a behavior that's similar to what Python (dynamically typed, duck typing and thus relatively weak typing) allows you to do:
Use C++'s builtin dynamic type mechanisms. Therefore, you need to create a so called polymorphic base class, that is a class that has at least one virtual member function (the destructor also works if you don't have a defined interface - it most often also must be virtual to avoid nasty issues). A short example:
struct Value { virtual void write_to(std::ostream &) const = 0; virtual void read_from(std::istream &) = 0; virtual ~Value() {} // Absolutely required!!! }; struct Number : public Value { int data; void write_to(std::ostream & stream) const { stream << "<Number " << data << ">"; } void read_from(std::istream & stream) { stream >> data; // Not the same format as write_to, shame on me } // Implicit destructor is fine }; struct String : public Value { std::string data; void write_to(std::ostream & stream) const { stream << "<String " << data.size() << " " << data << ">"; } void read_from(std::istream & stream) { stream >> data; // Not the same format as write_to, shame on me } };
Using this you can now for example store
Value
s whose actual type you can let the user decide:std::vector<std::unique_ptr<Value>> values; while (wantsToEnterMoreValues) { std::string choice = ask("What type of value do you want to enter?"); std::unique_ptr<Value> value; if (choice == "string") { value = std::make_unique<String>(); } else if (choice == "number") { value = std::make_unique<Number>(); } else { // launch apocalypse } value->read_from(std::cin); values.push_back(value); }
This is easily extensible to more types. Note that in order to use C++'s builtin dynamic typing you need to go without value semantics, but instead completely use reference semantics, either using real references, or (in most cases where ownership must be transferred, like in above example to the
values
vector) using pointers.The
dynamic_cast
approach works very similar to this, except that you're using runtime type information more explicitly and don't need a unified interface (but have much more work in order to maintain your code).Use the
union
language feature. This only has become really possible with C++11, where union members may be non-trivially construable:enum class Type { Number, String }; struct Value { Type type; union { std::string string; int number; }; Value(std::string const & s) : type(Type::String), string(s) {} Value(int n) : type(Type::Number), number(n) {} Value(Value const & v) : type(v.type) { switch (type) { case Type::Number: number = v.number; break; case Type::String: new (&string) std::string(v.string); break; default: break; // Launch nuclear missiles } } ~Value() { switch (type) { case Type::String: string.~std::string(); break; default: break; } } };
As you can see, this quite a lot of work. With this approach you can use value semantics, but cannot as easily extend your
Value
s to support more types. Moreover, due to using aunion
, you're going to waste some memory.
Bottom line: You need to implement the behavior on your own, but can do so in exactly the way you want it to behave. For example: You could also implement assignment operators operator=(Value const &)
that do implicit type conversions. You can also use the implementations from boost, like boost::any
or boost::variant
.
I'd like to reference two answers I've written on this site to the very same subject, perhaps they're also helpful for you:
- https://stackoverflow.com/a/32926607/1116364
- https://stackoverflow.com/a/32041381/1116364
Also some C code which is relevant, because it tries to solve the same issue: https://stackoverflow.com/a/35443434/1116364
Note: All code in this answer is written straight out of memory and not tested. It thus serves only as demonstration of the basic techniques.
回答2:
Unlike Python, C++ is a strongly typed language. This means that the type of each object is known at compile time.
Having said that, there is a very, very vague analogue that can apply in some circumstances.
If you have a pointer to an object whose class has at least one virtual method, a dynamic_cast
will either convert it to a pointer to the requested class, or to a nullptr
. This would only work when the most-derived object that's being pointed to includes both classes in its hierarchy, unambiguously.
来源:https://stackoverflow.com/questions/35834810/how-to-check-data-type-in-c