Today let us see how to write implementation of class methods outside of class body.
By writing class member functions outside, you are not exposing implementation to the user of the class. And if you have to change the implementation user is not affected.
circle.h
This is the declaration of the class.
Now let us write implementation of find_area function in another file circle.cpp
Note how we have to include the circle header file in this.
The find_area() function must be preceded by class name and ::. :: is called scope resolution operator. circle:: tells us that the function is member of circle class not a global function.
When we write definition of member functions outside of class, we have to add a prefix of class name and scope resolution operator.
Note : Scope resolution operator specifies the scope of the name. It is also used to identify the name space. To use cout and cin for I/O , we can use std::cout and std::cin, instead of using "using namespace std".
Finally we write our main function and user program in third file main.cpp
As this needs to use circle, this also includes circle.h
But how do we compile this program which is split into three different files?
g++ circle.cpp main.cpp
We have to compile our main as well as class cpp file together.
And the output of the program is
5.33388e+18u
Note: In future sample programs, I may not split the class into declaration and method definitions, just for the sake of simplicity.
Let us come back to output of the program. What is this and why do we get a different answer each time.
Because we have not initialized radius of the class. And we are not able to access it.
There must be some function we can initialize the data members of the class.
Such a method is called constructor.
Let us write our circle class with constructors.By writing class member functions outside, you are not exposing implementation to the user of the class. And if you have to change the implementation user is not affected.
circle.h
class circle { float radius; int x, y; public: float find_area(); };
Now let us write implementation of find_area function in another file circle.cpp
#include"circle.h" float circle::find_area() { const float PI = (float)22/7; float area = PI * radius*radius; return area; }
The find_area() function must be preceded by class name and ::. :: is called scope resolution operator. circle:: tells us that the function is member of circle class not a global function.
When we write definition of member functions outside of class, we have to add a prefix of class name and scope resolution operator.
Note : Scope resolution operator specifies the scope of the name. It is also used to identify the name space. To use cout and cin for I/O , we can use std::cout and std::cin, instead of using "using namespace std".
Finally we write our main function and user program in third file main.cpp
As this needs to use circle, this also includes circle.h
#include<iostream> #include"circle.h" using namespace std; int main() { circle c1; cout<<c1.find_area(); }
g++ circle.cpp main.cpp
We have to compile our main as well as class cpp file together.
And the output of the program is
5.33388e+18u
Note: In future sample programs, I may not split the class into declaration and method definitions, just for the sake of simplicity.
Let us come back to output of the program. What is this and why do we get a different answer each time.
Because we have not initialized radius of the class. And we are not able to access it.
There must be some function we can initialize the data members of the class.
Such a method is called constructor.
Constructor
A
C++ class has two special member functions called constructor
and destructor used for initializing and cleaning the object.
A constructor is a special member function of a class which initializes the object and is called automatically when an object is created. Constructor has same name as class, and it has no return type.
A constructor is a special member function of a class which initializes the object and is called automatically when an object is created. Constructor has same name as class, and it has no return type.
Here are some more facts about constructor
- Constructor has same name as class.
- Constructor has no return type. No, not even void!
- Constructor can have 0 or more parameters.
- Constructor can be overloaded - a class can have multiple constructors.
- Constructor is called automatically when an object of the class is created.
#include<iostream> using namespace std; class circle { float radius; int x, y; public: float find_area(); circle(float r);//constructor circle(float r,int cenx,int ceny); //constructor }; float circle::find_area() { const float PI = (float)22/7; float area = PI * radius*radius; return area; } circle::circle(float r) { radius = r; x = y = 0; } circle::circle(float r,int cenx,int ceny) { radius = r; x = cenx; y = ceny; } int main() { circle c1(7); circle c2(2,10,10); cout<<"Area of first circle: "<<c1.find_area()<<endl; cout<<"Area of second circle: "<<c2.find_area()<<endl; }
We have two constructors for the class - circle(float r) and circle(float r, int cenx, int ceny)
So the names of these constructors are circle - class name. They have no return type.
And also we did not invoke these constructors explicitly. We just created the objects c1 and c2.
ENDOFCODE
Output of the program:
def constructor of A
parameterized constructor of A
Number is 3
Constructor of B
Constructor of B
def constructor of A
def constructor of A
def constructor of A
def constructor of A
So the names of these constructors are circle - class name. They have no return type.
And also we did not invoke these constructors explicitly. We just created the objects c1 and c2.
Passing values to constructors
If a constructor is not called explicitly, how are arguments passed to it? They are sent within parentheses after the object name - c1(7), c2(2,10,10)
Default constructor
If a constructor takes 0 parameters or it has default values for all parameters, then it is called default constructor.
When an object is created without sending any values, default constructor is called. It is also called when an array of objects is created.
class A { public: A() { cout<<"constructor"; }/*default constructor*/ A(int m) { cout<<"parameterized constructor\n Number is "<<m; } }; class B { public: B(int n=0){/*code*/} /*default ctor*/ }; int main() { A obj1;/* calls default constructor*/ A obj2(3);/*calls parameterized ctor*/ B obj3;/* ok*/ B obj4(10);/*ok*/ A arr[4];/*calls default ctor 4 times*/}
Output of the program:
def constructor of A
parameterized constructor of A
Number is 3
Constructor of B
Constructor of B
def constructor of A
def constructor of A
def constructor of A
def constructor of A
Class A has a zero parameter constructor. And class B has a one parameter constructor, but has default value 0 for that parameter. So both of these are default constructors.
When a class has no user defined constructors, the compiler provides a default constructor for the class which is trivial.
class C { int m; public: void somefn(); };
Class C does not have any constructors. So compiler provides a default constructor which is trivial.
Now let us modify class A and remove the default constructor.
class A { public: A(int m) { cout<<"para. constructor\n Number is "<<m; } }; int main() { A obj1(9);/*ok*/ A obj2;/*error*/ }
Now if an object of A is created without argument as in obj2, there will be a compiler error. As A has a constructor, compiler is not providing default constructor. So obj2 can not be created.
Comment the only constructor of A class now. And observe what happens to A obj2;
Let us revise with few questions here.
Which of the following are valid default constructors of the class Rectangle?
- Rectangle::Rectangle(int side=0);
- void Rectangle::Rectangle();
- Rectangle::Rectangle(int s);
- Rectangle::Rectangle();
1 is a valid default constructor. Though it has a parameter side, there is a default value to it. Which means it can be called without passing any values.
2 is invalid because constructors do not have return type. Not void also.
3 is invalid because, this constructor has one parameter.
4 is valid default constructor.
Member Initializer Lists
A constructor can initialize data members using member initializer list . Initializer list is more efficient than assignment in constructor. The member initializer list is written like this
Number::Number(int m,int n):a(m),b(n) { cout<<"Constructor"; }
In the above example,
a(m),b(n) is member initializer list. Data
member a is set to m and b is set to n.
There are certain cases where
one must use member initializer lists. A class must use member initializer
list if
- it has constant members
- it has reference members
- it has base classes with no default constructors
- it has member objects with no default constructors
class A { int m; const int n; public: A(int x,int y) { m = x; n = y;/* error. Can not modify constant data*/ } }
In the above example, as the
class has constant member, you should use member initializer list for
constant n. you
should re-write constructor as
A(int x,int y):m(x),n(y){}
Comments
Post a Comment