For newer C++ programmers, classes can be a confusing topic, but they're actually quite simple to understand. Overall, for a programmer a class represents a 'plan' for creating objects, which is a set of data consisting of primitive data types and other objects, and class methods packaged together in one unit that you directly use in your program code, and those created objects are called instances.
My First Class:
Let's take a look at a very simple example of a class that contains nothing more than one data member and two methods:
Alright, let's take note of a few things here. First, you'll notice that this "class" seems to contain the functions within it's own brackets! This is how classes are built, and it resembles in many ways how structs are made in C (in fact, classes are an extension of C structs, and C++ structs are classes with public access). These are methods, and they're usually the way users of your class (namely yourself) will manipulate data members of that class and utilize that class in your programming.Code:class MyClass { int mynum; // This is a data member. public: void setNum(int a) // These are called 'methods'. { mynum = a; } int getNum() { return mynum; } };
Access Control:
The next thing you'll notice is that "public:" keyword, and it looks like a GOTO label from C. This, however, is not what it is, instead it's what is called an "Access specifier", which is a label describing what access other objects and functions have to the data members and methods of your class. Access control is an intrinsic part of C++, and no lesson on classes would be complete without it. Classes implicitly have all properties (data structures, objects, or primitives inside of a class) and methods (functions in a class) declared as private, which means ONLY the owning class can access them, and no one else can. In order to make it so other parts of your program can access those methods, you must declare them as public, using the "public:" access specifier. Finally, all classes must end with a semicolon, the same with structs. Other than that, this should be relatively straightforward (do not hesitate to ask questions!).
Using Classes:
So how do you use this class in your currently existing program code? Well, this is also easy, take a look at this main function:
The above code will print out "10" on the terminal window and end the program. You declare classes the same as you would any other data type. Further, you can access functions declared in the class similarly to how you accessed members in structs in C, using the . operator. Another thing to take notice about classes is they are all self contained, which means if I make another class, and call it "n", the instance of MyClass called "m" will be unaffected. Consider the below source code doing just that:Code:int main() { MyClass m; // This creates a new instance of MyClass called "m" // You can now use m using the interface provided in MyClass: m.setNum(10); std::cout << m.getNum() << std::endl; return 0; }
Now the program will print out "10 20" and close. What this exemplifies is that classes don't affect each other (except when using "static" properties, however this will be explained in a different tutorial).Code:int main() { MyClass m, n; // Two instances of MyClass, they're completely separate. m.setNum(10); n.setNum(20); std::cout << m.getNum() << " " << n.getNum() << std::endl; return 0; }
Passing Instances as Parameters:
Remember how I said you could declare a class just like any other data type? There's a lot more than just that in which that statement entails! In fact, in C++ Classes, or more specifically their instances, are considered first class objects, and as such can also be passed to other functions and methods as parameters, returned from functions and methods, and assigned to variables. Consider the following code example, showing the class we wrote above doing all of those things:
Classes can be treated in every way just like another data type!Code:void printValue(MyClass print) { std::cout << print.getVal() << std::endl; } MyClass afunction() { MyClass retVal; retVal.setNum(25); return retVal; } int main() { MyClass m, n; m.setNum(15); printValue(m); n = afunction(); printValue(n); printValue(afunction()); return 0; }
Constructors and Destructors:
Remember though, that since you're passing by value in the above example, each time MyClass is passed, a copy of it is created and another MyClass constructor (or ctor) is called, and every time a MyClass falls out of scope it's destructor (or dtor) is called. What are constructors and destructors? Well, they're functions you can write in your objects that run when your class is created (constructor) and destroyed (destructor). In fact, with our previous class we already had an empty constructor and destructor implicitly declared! Let's make that explicit, shall we, and allow for the user to pass in an argument! Modify the class like so:
You'll notice that both the constructor and the destructor do not have return types, and they both have the same name as the class. That is how these methods are special, they cannot return values, and they must be the same name as the class. Destructors always have a tilde (~) in front of the name, and this differentiates them from constructors.Code:class MyClass { int mynum; public: MyClass(int setVal = 10) // This is the constructor syntax. It never returns // a value, and it has a default value of 10 (optional). { setNum(setVal); // this is, of course, assumed to be a method of the class. } ~MyClass() // This is the destructor syntax. It cannot accept any parameters // nor can it return a value. Further, it also cannot throw exceptions. { std::cout << "MyClass being destroyed with value of " << mynum << std::endl; } void setNum(int a) { mynum = a; } int getNum() { return mynum; } };
Pointers to Instances:
You have to treat pointers differently than you would statically declared classes. Pointers are very useful with classes, but you must keep in mind the difference in syntax when using them. Below is a simple example using such pointers with our newly changed MyClass:
Multi-file Classes:Code:void changeValue(MyClass* mc, int i) // Notice the asterisk next to the name. { mc->setNum(i); // Notice the use of the arrow operator -> // This is how you access methods and members of the class referenced // by the incoming pointer. } void printValues(MyClass* m, MyClass* n) { // When using pointers, the arrow operator (->) essentially replaces the . operator std::cout << m->getNum() << " " << n->getNum() << std::endl; } int main() { MyClass m(15); // Notice that I pass a value to this class... MyClass n; // But not to this one (default is 10). printValues(&m, &n); // See the above tut on Pointers if this confuses you! changeValue(&m, 25); changeValue(&n, 50); printValues(&m, &n); return 0; }
Almost every piece of software you'll inevitably design will reside in multiple files. This is mostly for organization, and that keeping a single file program is very difficult to maintain. Well, classes, at least in C++, were meant to span two files, the header file and the source file. You only need to include the header file, and this will not only make your program more organized, but also reduce compile times. In order to accomplish this, all you've got to do is write a header file that, instead of placing function bodies into, you place function prototypes. Take a look:
You'll notice that the above class doesn't have any function bodies in it, instead just prototypes. This is perfectly fine in a header file, but somewhere you need to actually define what these are. You do this in the source file. Conventionally, the source file is given the same name as the header file, though this isn't required. I highly suggest it to keep your header and your source together. To define the functions, you must use this syntax:Code:// myclass.hpp header file #if !defined(MYCLASS_HPP) #define MYCLASS_HPP class MyClass { int mynum; public: MyClass(int); ~MyClass(); void setNum(int); int getNum(); }; #endif
You'll need to add "MyClass::" in front of each name, so that the compiler knows what you're referring to. This is very similar to a namespace, but not exactly the same. I highly suggest you learn to split up your code like this, it makes programs far more maintainable because any changes to the implementation of the class will not require you to recompile all of the other files that use the class.Code:// myclass.cpp source file #include "myclass.hpp" // You need to include the header! MyClass::MyClass(int set = 10) // This is the constructor { setNum(setVal); } MyClass::~MyClass() // This is the destructor { std::cout << "MyClass being destroyed with value of " << getNum() << std::endl; } void MyClass::setNum(int a) // Notice you still have to have the return type in front. { mynum = a; } int MyClass::getNum() { return mynum; }
"Struct" Instead of "Class":
If you learned about structs in C, you must notice that the syntax of using a class is very similar. So are structs the same as classes? Well, in C++, yes they are, in every way except one. In a Class, the default form of access control is "private", whereas the default form of access control in a struct is "public". This means that if you to change our MyClass from a class to a struct, like so:
You'd suddenly make int mynum a public variable that could be directly assigned to or used by other classes! In a few very rare cases, this is okay (for example, you're using an obvious data structure with no or few methods), but usually you want to apply some access control to it. This is why we use Class instead of Struct normally. C++ idioms, though, mandate that the public members should be first... so why not simply call everything a struct and place the private label with private data at the bottom? For most people, it's simply readability, and it really comes right down to what you prefer.Code:struct MyClass
Getting Deeper into Classes:
There's much more to classes than this, but this should be a great introduction. Another big subject that can really only be covered by it's own tutorial is inheritance, which allows for another class, called the derived class to "inherit" all of the protected and public members and methods of the first class, or base class. With this comes polymorphism, which I've touched upon with the use of virtual functions in this tutorial. Obviously both of these subjects are vast, and I couldn't do them justice here, but I can give you a sneak peak of the next tutorial on Dynamic Memory Allocation, which also uses classes and is another big part of classes! Take a look at the code below:
The above is a very simple Linked List implementation! When I get the Dynamic Memory Allocation tutorial done, you'll see why and I'll link you to it here.Code:class LinkedString { public: LinkedString(const char* value, LinkedString* other = 0) { next = other; word = new std::string(value); } ~LinkedString() { delete word; delete next; // Deleting null by definition is a non-op. } void makeLinkOnTail(const char* value) { if (next != 0) { next->makeLinkOnTail(value); return; } next = new LinkedString(value); } const char* getWord() { return word->c_str(); } const char* getWordAt(int loc) { if (loc > 0) if (next == 0) return 0; else return next->getWordAt(loc - 1); return getWord(); } private: std::string *word; LinkedString *next; };
That's it, I hope you found this to be informative, and stay tuned for the tutorial on Dynamic Memory and another on Inheritance and Polymorphism! Until then.![]()
Last edited by ZekeDragon; 12-11-2009 at 08:30 AM. Reason: Added link to Guest's Struct tutorial
Wow I changed my sig!
Nicely done. +rep
Great job, very easy to understand and follow from someone newish to C++.
Rep added!
*bump
This is great just thought I should bump it.
Thanks. It helped much. But i still need an easier tutorial. +Rep.![]()
nice one .. i like it .. +rep ..![]()
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks