Sep 12, 2016 learning C++ phys-492/592
int var = 3; // declare an integer with an initial value of 3
is easy to understand. int
declares the type of the variable var
to be integer. Following this concept, we can declare the type of another variable to be Human
:
Human mike;
Where mike
is the name of the variable, Human
is the type of the variable. This type is much more complicated than int
, but nevertheless, it is still a type.
It is easy to initialize an integer. All it takes is just a number. It takes much more to create a virtual human being in your code. For example, you may need to specify mike
’s height and weight. One =
sign is not enough. So we use the following syntax in C++ to specify more than one properties of a complex type:
Human mike(float height=1.75*meter, float weight=135*pounds);
Following the same idea, we can have
Fish salmon;
and much more. In C++, the complex type has a name called “class”. Human
and Fish
are hence classes. mike
and salmon
are called the object of class Human
and Fish
, respectively. They are variables of complex types.
Now, our mike
is hungry and he wants to eat fish. To describe this in our code, we can have
Human mike(float height=1.75*meter, float weight=135*pounds);
Fish salmon;
mike.Eat(salmon);
Eat
is a function that a Human
has. The dot in between mike
and Eat
is the way in C++ to call a function related to a complex type, which is called a member function of the class Human
. Having member functions is the biggest difference between a class (a complex type) and a basic type like int
. Basic types cannot DO things. Classes can.
Class Human
and Fish
is not defined in the standard C++ library. We will have to define them by ourselves before using them. This is how we do it in C++:
class Food // Fish is a type of Food, we define Food before Fish
{
public:
float fWeight; // class Food's member variable
// Constructor is a special member function.
// It has the same name as the class, returns nothing,
// and can be used to initialize member variables.
Food(float weight): fWeight(weight) {};
}
class Fish: public Food // class Fish inherits from class Food
{
public:
// Food's constructor is called in Fish's constructor
Fish(float weight=0): Food(weight) {};
// member function
void Swim(); // just a declaration, to be defined elsewhere
}
class Human: public Food // a human can be another human's food :)
{
public:
float fHeight; // class Human's member variable
// class Human's constructor member function
Human(float height=0, float weight=0): Food(weight), fHeight(height) {};
// member function
void Eat(Food food) { fWeight=fWeight+food.fWeight; }
}
Since a class is a complex type, we need probably more than one variables to save some settings of it, they are called member variables. Traditionally, member variables start with an f
to distinguish them from normal variables. Unless they are claimed to be public, they cannot be used outside of the class. Member variables can be initialized through a special member function called constructor, which has the same name as the class and returns nothing. As its name indicates, a constructor is used to construct (initialize is probably a better word) the class. When you declare a new object of a class, the constructor is called to initialize the object. There can be multiple constructors in a class, each of them gives a different initialization method.
Another interesting thing that a class can do but a basic type cannot is that a class can inherits from another class. As illustrated in our example, Fish
inherits fWeight
from Food
. By inheritance we avoid duplicating some variables or functions in multiple classes. For example, we can have class Human
and Bird
inheriting fWeight
from Food
as well. Food
is called the parent (or mother) class, Human
, Fish
and Bird
are children (or daughters) of Food
. Children classes all have the same member variables and functions inherited from their parent. In addition, they can have their unique features. For example, Fish
can Swim()
, Bird
can Fly()
.
Since a class is a complex type, the OS has to allocate a block of memory to store it. There are two ways to do it, the fast but short-lived way and the slow but long-lived way. The memory claimed in the former way is called the stack
. The memory claimed in the latter way is called the heap
. A professional description of the stack
and the heap
is available in stackoverflow. As an end user, you just need to remember the followings:
stack
than in the heap
.stack
can only live till the end of its scope. An object stored in the heap
can live till the end of the program or till it is explicitly deleted in some other place in the program.In the examples above, all the objects are declared in the stack
. The way to declare an object in the heap
is the following:
Human *jack = new Human(float height=1.90*meter, float weight=158*pounds);
We say that jack
is a pointer, pointing to an Human
object allocated in the heap
using the new
operator. This piece of memory can be manually deleted this way:
delete jack;
Keep forgetting deleting memory blocks allocated in the heap
in a long-running program can cause a big problem called memory leak, as the program claims more and more memory as time goes by. This is not as serious in a program that only runs for a very short period and does not claim memory blocks constantly in the heap
, because the occasionally leaked memory will be freed anyhow when the program ends.
The way to call a member function using a pointer is the following:
jack->Eat(mike); // use -> instead of . to call member function
Activities mentions in this site have been supported by the following grants: