Classes and objects
A class such as Dog is a blueprint. It describes a type, but it isn't a dog you can use. An object, also called an instance, is a real value of that type, with its own place in memory. This lesson is about making objects from a class that already exists.
Creating an object on the stack
In C++, you create an object the same way you create an int variable: write the type, then a name.
Dog rex;
That one line creates a Dog object named rex. There is no new. Languages such as Java and C# need new for every object, but in C++ an ordinary variable declaration constructs the object directly. The object lives in the enclosing block's local storage, usually called the stack, and it is destroyed automatically when the block ends.
Many objects from one class
You can create as many objects as you need. Each declaration makes a separate one:
Dog rex;
Dog buddy;
Dog luna;
The three variables have the same type, but they are three different objects with different addresses. Once a class has member variables, each object gets its own copy of them, so changing rex never changes buddy. Copying works the same way: Dog copy = rex; creates a new object whose contents start out equal to rex, and the two are independent from then on.
Automatic cleanup
A stack object has a clear lifetime. It is created where it is declared and destroyed at the closing brace of its block. When several objects are declared in one block, they are destroyed in the reverse order of their creation. A class with a constructor and a destructor shows it:
class Pup {
public:
string name;
Pup(string name) { this->name = name; cout << "built " << name << endl; }
~Pup() { cout << "gone " << name << endl; }
};
void demo() {
Pup a("A");
Pup b("B");
cout << "in scope" << endl;
}
Calling demo() prints:
built A
built B
in scope
gone B
gone A
You wrote no cleanup code in demo. This automatic cleanup is one of the main reasons C++ programmers prefer stack objects.
The heap alternative
C++ also has new. It allocates the object on the heap and gives you back a pointer:
Dog* rex = new Dog();
// ... use rex->...
delete rex;
Here you are responsible for calling delete exactly once. Forget it and the memory leaks; call it twice and the behaviour is undefined. Heap objects are useful when an object must outlive the block that created it or when its type is only known at run time, as in the polymorphism lesson. For everything else, prefer the plain declaration.
A trap: empty parentheses
When a class has a constructor that takes arguments, you pass them in parentheses, as in Dog rex("Rex", 4);. But if you want to call the constructor with no arguments, do not write empty parentheses:
Dog rex(); // declares a function named rex that returns a Dog
Dog rex; // creates a Dog object
The first line is parsed as a function declaration, not an object. The compiler may warn about it, and a later use such as rex.name fails with an error about a non-class type. Leave the parentheses off, or use braces: Dog rex{};.
The lesson's exercise
The Dog class is given. The task is to create three Dog objects named rex, buddy and luna inside mainFunction. The lines that follow use sizeof on each variable, so each name must exist, and they print:
rex exists
buddy exists
luna exists
Each step adds one declaration: type first, then the name, then a semicolon. The names must match exactly because the lines below refer to them.
The solution in C++
class Dog {
};
class Solution {
public:
void mainFunction() {
Dog rex;
Dog buddy;
Dog luna;
if (sizeof(rex)) cout << "rex exists" << endl;
if (sizeof(buddy)) cout << "buddy exists" << endl;
if (sizeof(luna)) cout << "luna exists" << endl;
}
};
The sizeof checks are only a way to make the program mention each variable. sizeof(rex) is the size in bytes of the object, which is never 0 in C++, so every condition is true. The variables are declared inside mainFunction, so they exist only for the duration of that call.
Common mistakes
- Using
newby habit.Dog rex = new Dog();doesn't compile in C++, becausenewproduces aDog*, not aDog. - Writing
Dog rex();with empty parentheses, which declares a function. - Using a name before declaring it. The variables must appear above the lines that use them.
- Believing that objects share state. Each variable is its own object.
Key takeaways
- Declare an object like a variable:
Dog rex;. Nonewis needed. - Every declaration makes a separate, independent object.
- Stack objects are destroyed automatically at the end of their block, in reverse order of creation.
newcreates a heap object that you mustdeleteyourself.