I know exactly what you're going through. I couldn't understand classes, at first, either. I LOVE them now (they make life so much easier).
Classes are interesting: they allow you to create objects with properties. They are not functions, so they abide by different rules.
Classes have members:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
class myclass{
public:
//constructor with an initializer list
explicit myclass(const int& arg1, const int& arg2) : memb1(arg1), memb2(arg2) {}
myclass() //default constructor, with no initializer list. Can/favorable to have one though
{
this->memb1 = 0;
this->memb2 = 0;
}
~myclass(){} //destructor.
myclass& operator=(const myclass& arg1)
{
this->memb1 = arg1.memb1;
this->memb2 = arg1.memb2;
return *this;
}
int get_memb1() const
{
return this->memb1;
}
void set_memb1(const int& arg1)
{
this->memb1 = arg1;
}
private:
int memb1, memb2;
};
|
So, there are quite a few things I'm throwing at you.
To start with your current situation, constructors return nothing. Constructors can take arguments, but they can't return anyhting. Constructors only construct the object by executing member functions, or initializing variables.
The first, and most obvious is the new
explicit
declaration. This basically says to (only) constructors to ONLY take that kind of argument. For example, if you do not define
explicit
for a constructor that takes a string, you can pass a
char*
to the constructor, and the conversion will take place. If explicit is defined, though, and you try to pass a
char*
to a constructor that takes a different argument type, then no conversion will take place. Basically, if you declare a constructor as
explicit
, you're telling it not to take any other kind of argument than the one you explicitly defined. (passing a float to an int constructor is another example) I have experienced weird things happen when I don't use explicit when I include operators (specifically operator=()). I would highly recommend declaring constructors that take any arguments as explicit. Templating classes can make them more flexible, but that's more advanced, I'm sticking to the basics for now.
The second thing you will notice is the wierd text after the explicitly defined constructor. That is an initializer list, and I have read that it is a performance boost, especially if you're only using that constructor to initialize. It will limit your declarations to calling the contructors directly, but that's good practice anyway (it's faster). The brackets on the end (
{}
) contain the function itself. Since the initializer list does everything we want it to, we don't put anything in there (you can , though, if you want).
The third thing is the default constructor. I prefer using an initializer list (performace!!!), but for the sake of demonstration I have used the function emplementation for you. You can decide later what you like better. Always include a default constructor when you have variables.
The next thing is the destructor. Again, it's in-line. Since the destructors of the
int
variables are called when the class is destructed, we don't need to put anything there. We would have to use this, though, if we allocated memory or used pointers. aka: if we used
int* memb1
instead of
int memb1
.
Next is the operator. This one takes a class arg. It's always good to have a copy operator. By definition, a class can always construct using it's own type, so you don't need to define the constructor for it, but the operator is not included by default.
next is the member function
get_memb1() const
. Notice the
const
at the end of the declaration. That tells the compiler that the function can not modify any member variables of the class. It's good practice to use the
const
definition when declaring a function that you don't want modifying member variables.
Also note the
this
pointer. That pointer points to the instance of the class. If you understand pointers, it should be self-explanitory.
this->
will dereference the pointer and call a member at the same time.
*this
is the equivilant of the class itself (it dereferences the pointer, returning the class).
You'll also notice that I'm passing arguments by using their constant adress.
const int&
, for example, passes the same instance of that integer. It does not create a new integer. If you were not to declare it
const
, you would be able to modify the exact same variable that you gave to it, that existswithin the calling function. Const correctness is somthing that is good practice.
If you have any more questions, feel free to ask! :D
I find it helpful to think of classes as a way to combine both data and instructions to use that data. They keep all the messy argument passing inside, so that all you have to do is see the members of it.
aka:
instead of calling:
do_this(_this, that, somthing_else);
you can simply:
why_not.do_this();
If you use the
explicit
declaration, the compiler will not allow you to "call" the constructor outside of initialization (which is bad practice to begin with). You should either declare the variable public, or create a getter function (a function that returns the vairiables). If you prefer to use a getter, here's how:
define the function:
1 2 3 4 5 6 7 8 9 10
|
void get_the_vars(int&, int&, int&) const;
//in the .cpp file...
void your_class::get_the_vars(int& one, int& two, int& three) const
{
one = this->memb1;
two = this->memb2;
three = this->memb3;
}
|
when you call the function, then the variables you passed will be modified by the function.
Edit: +1 mutex