- Feature Articles
- CodeSOD
-
Error'd
- Most Recent Articles
- Named And
- It's About Time
- Scrollpocalypse
- Fast Quick
- 12345
- Said Different
- Ai Dios Mio
- Unrewarding
-
Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
God. This had me laughing.
Admin
The type check seems to be unnecessary anyway. GetFirstTentacle is clearly allowed to return null, even if called against an octopus or squid (presumably some of them have lost all their tentacles). So there should be no issue skipping the type check and calling GetFirstTentacle anyway. If it's a cat, it should just return null - we don't care what it is, just that it has no tentacles to steal. Which also means that if someone adds a tentacled cat to the system it won't break this function. .
Admin
Sadly incorrect. An octopus has arms rather than tentacles, and there are plenty of species that aren't octopuses or squids that have tentacles of some sort, including one species of mammal, the star-nosed mole.
It will, indeed, work, in that it will do what it is supposed to, and cross-casting like that is not part of what it is supposed to do. The return value will be
NULLor, more modernly,nullptr, if you try to cast between two classes that are not part of the same inheritance tree. (If there's a class DogCat which derives from Cat and from Dog, and you have a pointer to the Cat part of a DogCat, then you can dynamic_cast fromCat *toDog *and you'll get the Dog part of the same object that the Cat part is part of. But in general, you can't do an arbitrary crosscast.Bad programmer! There are legitimate uses for C-style casts in C++, but a certain amount of care is needed, and they shouldn't be used as a substitute for the correct C++-style cast (in this case, it's not necessary anyway, since
dynamic_castwill search through the inheritance tree of the object from any starting point). (There is only one thing that you can do only with a C-style cast, namely (static) casting to a private base class that's actually a base of the requested object, which is something you shouldn't do anyway.)More correctly, const_cast removes "cv qualifiers", i.e.
constand/orvolatile.Admin
Also curious as to how it treat sentient tentacles that come in green and purple hues.
Admin
I think some people missed the point. Instead of having an override function that says "you're an animal, do you support tentacles, yes/no?" the base class is checking what derived class was passed in to decide. The code is anonymized so it could have been something else not tentacle-related like "can you fly?", "do you breathe oxygen?", "can you sting people?", etc....
Admin
They're already applying that optimization to the animal you're stealing a tentacle from. They "have" to do it here to enforce the same constraint on the animal you're stealing the tentacle to.
Admin
Yes. Complaining about the type of cast or how the class of a parameter is being determined is a bit like complaining about the colour of the iceberg that hit the Titanic.
There should be a definition of
getFirstTentacle()in the base class that always returnsnulland it should be overridden in classes that have tentacles.However
It does look like any
Animalcan attach a tentacle to itself, even if it wasn't born with any, so perhaps the implementation should include a tentacle collection in the base class which starts empty for mostAnimals and is populated with 8 or 10 tentacles in the constructors forOctopusandSquidrespectively. The functions can then be fully defined inAnimalAdmin
Dang! My octopus lost an arm! I'm checking the manual, but I can't find a number for tentacle support.
Admin
To Remi's opening point: Back in the '90s, when I was first introduced to OOP, tutorials indeed liked to use animals, as well as vehicles. (I especially recall bicycles, but cars were in there, too.) None of it made any sense whatsoever, until I found something that explained object-oriented programming in terms of programming. It made perfect sense then. Gosh. Imagine that.
Admin
Has nobody noticed that the code is checking if
thisis an Octopus or Squid, and notanimal? An octopus can steal a tentacle from a cat, but a cat can't steal a tentacle from an octopus.Admin
The other common examples I remember were shapes: Square IS-A Rectangle IS-A Quadrilateral. They would relate it to programming a graphics drawing or rendering application.
Vehicles were often used to show the distinction between IS-A and HAS-A. Automobile HAS-AN Engine, Sedan IS-AN Automobile.
Admin
And shapes is one of the first places where you'll get in trouble with the analogy. A square is-a rectangle where all of the sides are the same. and/but A rectangle is-a square that also has a separate length property. So which one is it? Neither one provides a fully satisfactory answer, depending on the situation and what you're trying to do with them. (though more likely you'd go with they're all Shapes (that are quadrilaterals), some of which happen to satisfy certain criteria).
Admin
If square derives from rectangle, then a rectangle with equal length and width isn't a square according to the type system, which is a bit unfortunate. But anyone who models rectangle to derive from square because they just both happen to share a width property is truly insane.
Admin
To be clear, I agree that the shapes analogy is quite poor and falls apart almost immediately, but having some type derive from some other type because they happen to share some arbitrary set of properties or functionality is always a recipe for bad code. In the square/rectangle example, assuming inheritance should be used at all (or that square should even be a separate type), the only sensible answer is that square derives from rectangle, simply because all squares are rectangles, and not all rectangles are squares.
Admin
How DARE YOU bring actual SCIENCE to a discussion!!!
Admin
I think this article misses the point a bit: It's not inheritance that confuses inexperienced developers, it's actually multi-inheritance. There is no single-is relationship, there can actually be multiple is-es with multiple sub-instances. Hence type-casting is way less straight forward and especially young devs with zero experience in multi-inheritance go sometimes a bit crazy with their limited understanding.
Admin
It can work in the sense that a Rectangle type would have two separate size fields where as a Square type would have just one. It may all come down to what the needs are, though I do agree that it might not be the best example to learn about inheritance from.
Admin
I'm like that. Not sorry.
Admin
Pretty much this, although I prefer to phrase it in terms of the Liskov Substitution Principle, where we note that according to the LSP, (paraphrasing "slightly") if we give a Square that's derived from Rectangle to a bit of code that expects a Rectangle, it should not be able to tell that it isn't a base Rectangle. See for example this pseudocode:
LSP says that the assert() should be OK because we think we're dealing with a Rectangle. Reality says that it explodes because we're dealing with a Square.
Conclusion, this version of "Square IS-A Rectangle" is bogus. (If they are immutable, like Java and C♭ strings, that might change, but in any case, the above situation invalidates the unqualified "a Square IS-A Rectangle" statement. It has to be qualified by "if they are immutable".)
Admin
An easy way around that problem is to have
Squarenot usewidthandheightbut a separate field, likesize, and its ownget_areathat multipliessizeby 2. It might also be better to haveSquarederive fromShapeinstead ofRectangleor perhaps haveQuadrilateral, that derives fromShape, and is the base for bothRectangleandSquare(as well asRhombus,Parallelogram,Trapezoid,Kite, etc.)Addendum 2026-10-14 08:42: Oops, that should be:
its own get_area that multiplies size by itself.
Admin
You're missing the point. Square is a property of rectangles that satisfy a certain constraint. When we talk about classes, objects, and inheritance, we're not talking about mathematical properties, but data representations. So you might represent a Rectangle with a length and width, and a certain subset of those representations are square. A data representation of a Square will have a single size parameter; therefore, Square does not extend Rectangle, but constrains Rectangle.
This is why Interfaces are preferred over inheritance. Square and Rectangle both satisfy the conditions for IRectangle (having Length and Width getters), allowing a Square to sit anywhere you need an IRectangle, but not when you need a Rectangle.
Regardless, this is all a very bad idea, as abstract shapes have no idea how to render themselves. As soon as you want to, heaven forbid, draw a shape, you need to know its details, which means knowing every single shape that can exist. Similarly, if you want to do collision detection, or calculate shape intersections. As long as shapes are simple data representations, all of this is easy. Once you apply the principles of OOP and hide the implementation details, these real-world tasks become almost impossible.