Lua and fake Typecast
I'm working with Lua and C++ (using LuaWrapper) and I'm having trouble with something. Let's say I have these classes:
class Bar{...};
class Foo
{
...
std::map<std::string,Bar*> _barlist;
...
Bar* getBar(std::string key)
{
return _barlist[key];
}
}
class BarDerived1 : public Bar{...}
class BarDerived2 : public Bar{...}
I have access to Foo
and Foo::getBar()
from Lua , the thing is that the type from the object returned is Bar
and I don开发者_如何学编程't have access to its BarDerivedX
methods.
As I understand it, Objects/Classes in Lua are simply MetaTables with functions assigned to keys, so I was wondering if there's a way to copy these extra functions from the BarDerivedX
class to the Bar
object (and would that even work?), also, is this the best way to do it or should I cast it in C++ before letting Lua access it?
The purpose of polymorphism, in any language, is to not have to care exactly what type something is. If you give someone, whether Lua or C++, a Bar
object, then Bar
should have the interfaces that the people need to do whatever they need to do.
That's the purpose of virtual functions. A virtual function defined in Bar
can be overridden with a different behavior in BarDerived1
. Other code doesn't have to know that they are being handed a derived class; they can just take a Bar
like always.
There are generally only two reasons to make a class derived from another. The first is polymorphism: you want to specialize a class by altering the behavior of certain functions.
The other reason is to gain access to its implementation. For example, if you're making a Unicode string, you could use a std::basic_string to store the encoded data. You could then privately derive from std::basic_string, thus allowing you to gain the storage optimizations that std::basic_string has, but you provide a different interface (since private inheritance doesn't allow the outside world to know that you derived from it).
If you want everyone to use Bar
objects that can have different behaviors based on derived classes, then you should be using virtual functions and polymorphism. However, if you are changing the interface in derived classes, then that's probably a sign of a design problem. Maybe those derived classes shouldn't be derived classes at all. Maybe they should be entirely separate classes that a Bar
instance may or may not have, based on some initialization parameters.
It's hard to say more without specifics on what you're actually doing. But in general, if you're using inheritance-based polymorphism correctly, you shouldn't need to cast from a Bar
to more derived versions. Just use the Bar
interface.
There is a basic principle in class inheritance:
It must be possible to interchange an instance of the superclass by an instance of any of its subclasses.
If B is a subclass of A, then in any places where you use an instance of A, you should be able to use an instance of B.
If your code isn't doing that - then simply you are not using inheritance correctly. Definitively, you are not using it correctly if the only reason you need a subclass is to make is simpler to create a collection.
As others are saying, a proper solution is to use a "generic type" on the collection declaration; Remove Bar
completely, and in the collection declaration, use boost::variant
, null pointers or the equivalent in your toolset.
精彩评论