With the release of newer VC versions, Microsoft not only introduced Managed C++ (VC7), and took that to a new level under the new name of C++/CLI (VC8). They also made some additions to the native C++ language. While neither VC7, 7.1 nor 8 should be considered "hot off the press ", I'm sure many still haven't ventured into these new constructs. A sound choice, perhaps. In either case, some exploration is due.
__interface
__interface IFoo
{
void doFoo();
};
class Foo : public IFoo
{
public:
void doFoo()
{
// do the foo
}
};
The __interface keyword, as horrific as it seems (I may be too much of a code poet (disregard my old hexdump post)), it can be useful in some situations. While classes in C++ can be implemented with the same "features" as those implied by an __interface structure, the latter will force you to use them. This means that with a __interface, there's no chance for you to
- include implementation in the interface
- inherit anything other than interfaces
- include anything but public pure virtual functions
- include data members
- ... and so forth
When you're poking around with your UML diagrams, trying to figure out what goes where, and wind up introducing logical interfaces, C++ has been somewhat awkward. While there's nothing preventing you from creating a class which behaves like an interface, no laws have enforced the consistency of the pseudo interface product. Given a large project, with several devs, you could easily find yourself having some meanie introduce, say, a data member to your "interface" class. Not only would that break your code, it would also break all project schematics.
So the point, as I see it, of the __interface structures, is to enforce some rules which have previously been restricted to comments, coding conventions and syntax verifiers. As such, it's a good thing. Whether or not you should use it, that's an entirely different story (and covered later).
Explicit overridesIn a scenario where you've got a class which inherits two or more interfaces, you may wish to change the behavior of a derived implementation, based on which interface the function is being called through. So along with the introduction of __interface, came the ability to override functions in specific interfaces.
__interface IFoo
{
void doFoo();
void doBar();
};
__interface IFoo2
{
void doFoo();
void doBar();
};
class Foo : public IFoo, public IFoo2
{
public:
void doBar()
{
}
private:
void IFoo::doFoo()
{
// doFoo called on IFoo ptr/ref
}
void IFoo2::doFoo()
{
// doFoo called on IFoo2 ptr/ref
}
};
Foo f;
f.doFoo(); // C2668: ambiguous call to overloaded function
f.doBar(); // Ok, calls Foo::doBar
IFoo2& if2 = f;
if2.doFoo(); // Ok: calls Foo::IFoo2::doFoo
Now the usefulefulness of this construct is questionable. Not to mention that it enables you to write structures that are less than intuitive to an end-of-the-line user. To elaborate: in the example above, doFoo will never be callable on an instance of Foo, unless you cast to a specific interface. doBar, on the other hand, is callable in any case. I'm not saying there aren't cases where this could come in handy, but if you wish to use it, give a second thought to how it'll to your next of kin.
for each The "for each in" principle is something many other languages have had for quite some time. C# has it, Java has it (though not with the "each" suffix), and so do most script languages you can come up with. If applied properly, it simplifies iteration, and contributes to not only better looking -- but also generally more intuitive -- code. With VC8 this feature was introduced to native C++, and there's really no voodoo to it.
While you'd normally iterate a vector in a way such as
vector<int> v;
for(vector<int>::iterator i = v.begin(); i != v.end(); ++i)
{
// do whatever with *i
}
The "for each" keyword enables you to do the same thing:
for each(int i in v)
{
// do whatever with i
}
That sure looks better to me.
By now, I'm sure all die-hard C++ enthusiasts are strangling the bejesus out of anything in near vicinity. Rest assured, though, I'm not pitching these constructs as something you should carelessly embrace. While they can all be handy, there's the inevitable conformance and portability matters to consider. If you were to embed this deep within a project, you can kiss any cross platform code reuse good-bye. We obviously wouldn't want that.
Use them as you see fit, I say. And even more importantly: now you know that they exist, and you won't loose face by loudly proclaiming that "That code couldn't possibly compile!!!11".