Mysterious Mysteries (Optional)
This page is optional (although you do still need to visit it, which you clearly have!). It's here for those who are curious about the differences between C++ and Java, and in particular, how C++ allows you to do things that Java doesn't let you do, and why you see new
so much more in Java code than in C++. If you're not curious, you can skip this page and move on to the next one.
Mysterious Mysteries Demystified: Familiar Syntax
Sherlock, if we were going to allocate an object on the heap, what would that look like?
Why, my dear Dr. Watson, it would look like this:
Cow* buttercup = new Cow{5, 3};
Gasp! That looks like Java!
Sure does!! I'd say
Cow buttercup = new Cow(5, 3);
It really does. Do you know why?
No! Tell me! Telll mmeeeeeee!
I know!! Because in Java, every object is allocated on the heap and every variable that refers to an object is a pointer variable!!!
Whoa…
What do you get in Java if you try to use a variable that you haven't assigned anything to?
A
NullPointerException
? Oh. My. Dog.I'm so embarrased about that exception name. We'd been so good about pretending there weren't any pointers by just calling them “references” everywhere instead to help everyone be chill with so many
pointers, uh, indirections, and then we had to go and name an exception after a pointer. We forgot just one time and it's been haunting us ever since. I blame a late night and too much… uh… cake, yeah, that's it.As we've discussed, a null pointer is a pointer with the value
nullptr
, which is not a valid address. A null pointer essentially means “not a valid pointer”.Java default-initializes all pointers to be null precisely so it can know to raise this exception if you haven't assigned a valid address.
Whereas C++ default-initializes pointers like they were primitive numeric types: with whatever is already at that spot in memory. As usual, that behavior means less overhead but more danger.
Mysterious Mysteries Demystified: toString
Have you ever called
toString
on an object in Java where you didn't specifically define atoString
function?Sure, it just gives you some gobbledygook.
Oh, but it's not gobbledygook. You get something like
Cow@458ad742
, right?Yeah, exactly. The part before the
@
is the class name, but after that it's just some garbage.No, it's a number!
That can't be a number! It has letters in it!!
It's a number in hexadecimal (base-16) notation. Instead of the digits 0, 1, 2, 3, 4, 5, 6, 8, and 9 (for base-10) hex numbers use the “hexits” 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f.
So that number (
0x458ad742
) is actually (2 × 1) + (4 × 16) + (7 × 162) + (13 × 163) + (10 × 164) + (8 × 165) + (5 × 166) + (4 × 167).So that's a really big non-negative number—
It's 1,166,726,978!
—do you know what that number represents?
No, no. It can't be!
It's the memory address of that object on the heap!
I'm dead. I'm literally dead. This killed me.
Maybe a jolt of caffeine will help bring you back to life? And like, pointers are cool, even if I'm a bit ashamed of them and try to hide them sometimes.
Mysterious Mysteries Demystified: Unfamiliar Syntax
So the reason for some of the unfamiliar syntax in C++ is that C++ allows you do something that Java doesn't!
In Java, every object is on the heap!! And you always interact with objects through a pointer!!!
But in C++ you can put objects in the stack! You can put objects directly inside other objects (rather than pointers to objects)! You can directly access an object or you can indirectly access it through a pointer.
Which can explain a lot!
Why is there no Java equivalent to
Cow mabel{3, 2};
?Because that C++ code declares an object on the stack and Java doesn't let you do that!
Why does C++ have both the dot operator and the arrow operator to access members?
Because one is for objects and one is for pointers to objects.
Java only has pointers to objects, so Java only needs one member-access operator (we chose the dot operator).
This is incredible! (I'm okay!)
But all that choice makes C++ more complicated. In Java, we like to have some mental space to think about things like factory factories and abstract factories and factories that make factories that make factories, and so on. But in C++, you can just put a
Cow
in aBarn
and be done with it!
Mysterious Mysteries Demystified: Initialization List
Talking about being needlessly complicated, what's up with initializer lists?
Well, when an object is created we need to initialize all of its member variables before the constructor starts.
Remember from the data lifecycle lesson: We can't use a variable until it has been initialized!
Java doesn't need initializer lists because every variable that refers to an object is a pointer. All the pointer members in Java can be default-initialized to null pointers, and then reassigned later.
In C++ it's possible for an object to “contain” an object; like a
Barn
containing aCow
(rather than containing a pointer to aCow
).So when we allocate and initialize a
Barn
, we must also allocate and initialize theCow
in theBarn
.All of that happens before we start running the code (inside the braces) in
Barn
's constructor! Otherwise, we'd start the body with some garbage memory where theCow
object is supposed to be and we couldn't expect any of theCow
methods (including assignment!) to work properly in that scenario.Since
Cow
has no default constructor, we can't default initialize it. There's no such thing as a “nullCow
”.We need to give parameters to the
Cow
constructor before we enter the constructor forBarn
.That's what the initializer list is for!
I kind of, sort of get it. I think.
Yeah, it's a lot. The point is that C++ needs initializer lists because it allows direct access to objects, whereas Java only allows access through pointers.
You can really see the design philosophies of these languages in play here. C++ focuses on programmer choice and minimal overhead: put objects wherever you want them and only use pointers when you need to.
When Java came along, it limited how you could allocate and interact with objects, trading some of that freedom for the sake of simplicity and safety.
Both philosophies are important and valid! There are lots of programming languages because there are lots of different problems and lots of different programmers!
In reality, whenever language designers try to make a language “simpler” to be easier to use, programmers themselves just make it all more complicated again by building more and more complex libraries or coding idioms on top of it. So real-world coding in just about any language is going to get complicated somewhere along the way. Each language ends up with its own internal culture that is a reflection of the language's design philosophy and the kinds of problems it's used to solve, but may be tricky to learn for newcomers.
(When logged in, completion status appears here.)