Abstract Data Types in C++

Read these sections, which discuss the foundation of ADTs and the way they are implemented in C (as structures) and C++ (as classes). The Standard Template Library (STL) is now officially part of C++. The STL continues a natural progression from structures (data only) to classes (data plus operations on that data) to a library of trusted classes that implement often-needed data/method containers. Since the STL is largely data-type agnostic, templates begin to be very useful.

Intermediate C++

Builds upon the foundation principles of C/C++, introducing the concept of Object Oriented Programming, the fundamental concept of which is the creation of objects.

Objects can be thought of as independent smaller self-contained mini programs that each have their own name, data and logic, and interact with one another to form a whole application.

OOP is intended to make thinking about programming closer to thinking about the real world, where an object's attributes and behaviours are bundled together.

The three pillars of OOP are Encapsulation, Inheritance and Polymorphism.

This section of the site covers C++ OOP, and also some of the more advanced techniques in C++

Classes and Objects

A class is a user defined abstract data type that further expands upon the concept of a structure but instead of containing just data, it also includes functions.

In OO parlance, functions within a class are referred to as methods.

The concept of enclosing data and functions together within a single entity is referred to as Encapsulation.

Strictly speaking, as far as the compiler is concerned, the only difference between a structure and a class is that of accessibility (aka visibility). A structure's members are all public by default, whereas a class's members are all private by default. However, it is normal programming convention not to mix the two up and therefore structures are generally used for data (or POD: Plain Old Data), and classes are used for objects.

A class consists of three elements:

  • Identity
    • Name for the class
  • Attributes
    • Data members
  • Methods
    • Function members

A class is akin to a blueprint or plan of how to make an object, that declares its attributes (member data types) and methods.

A class is declared by use of the keyword class

  • followed by the user defined identity name for the class (akin to a primitive data type, e.g. int)
  • followed by the class members enclosed within a set of { curly braces }
  • followed by optional object identifiers
  • followed by a semi-colon ;

Syntax:

class identity {
    public:
        members ;
    private:
        members ;
    protected:
        members ;
} objects;

The keywords public, private and protected are known as the access specifiers, which define the level of visibility of a class's members.

Once the class has been declared, an object is declared just like any other data type (e.g. int x;).

Extremely simple Class example:

Simple Class

1 #include <iostream>
2 using namespace std ;
3 
4 class Triangle {
5 
6 public:
7 	float width ;
8 	float height ;
9 
10	float area(){
11		return ((width * height) / 2) ;
12	}
13 } ;
14 
15 int main () {
16 
17 	Triangle myTriangle ;
18 
19 	myTriangle.width = 5 ; //member access using the .dot operator
20	myTriangle.height = 6 ;
21
22	cout << "Triangle area: " << myTriangle.area() << endl ;
23
24 	return 0;
25 }

Compile & Run:

Triangle area: 15

The above example is overly simplified to show a function being used within a class. Normally all attributes (in this case the two floats on lines 7 and 8) should be private to ensure that only the object itself is responsible for any changes of its own data.

An object is said to be instantiated, by declaring a new identifier against the class's identity (i.e. the abstract data type), as per line 17 above.

Encapsulation

The concept of combining attributes and methods (data and functions), collectively referred to as members, into a single named object / entity.

Access / visibility of the members is controlled by access specifiers that define what is presented externally (public) and what is kept hidden (private).

Since an object should be responsible for its own data, only its public methods should be used to manipulate its data, and it is these public methods that are considered as its interface.

Only the barest minimum should be publicly visible and utilised externally.

Any invoking object should not care how the requested object's methods are implemented, all they should care about is presenting the required information via a message to the object's public interface in the correct format, so that it can receive an expected return or action.

Access to an object's attributes should only be controlled by the object itself, and no other object should directly change an attribute of another object.

This concept is known as data hiding.

This is akin to the black box model. We don't care what goes on inside as long as we get what we want from it, providing we supply the correct information to it.

So as long as the interface stays the same, the internal methods of the object can be changed or improved as/if required.

Reduces complexity and dependencies, so that a change in one place won't require multiple changes elsewhere.

In this example, objectA is instantiated on line 26, we then access its public set method to give values to its private data members, and finally we access those private data members using the public get methods on line 30:

1 #include <iostream>
2 #include <string>
3 using namespace std;
4 
5 class MyClass{
6 	private :
7 		string first, second ;
8 
9 	public:
10		void set(string x, string y){
11			first = x ;
12			second = y ;
13		}
14
15		string getFirst(){
16			return first;
17		}
18
19		string getSecond(){
20			return second;
21		}
22 };
23
24 int main() {
25
26	MyClass objectA ;
27
28	objectA.set("Hello, ","World!") ;
29
30	cout << objectA.getFirst() << objectA.getSecond() << endl ;
31
32	return 0;
33 }

Terminal:

Hello, World!

 

Access to the object's private data is completely controlled by the object itself. We cannot directly access (set or get) at its attributes without using its own methods.

Interface Vs Implementation

This concept focuses upon separating what an object does from how it does it.

This concept goes hand in hand with encapsulation, data hiding and abstraction in providing the foundations for OOP.

Specifically, Interface is the public methods of a class that control how it behaves. Whereas implementation is the actual workings of how it behaves.

For instance, slightly modifying the previous example, the class now simply declares its interfaces within the class declaration.

The implementation has been defined outside of the class declaration, but is associated via the scope resolution operator ::

Thus, this class's interface can be seen on lines 10, 11 and 12, and their according implementations on lines 15, 20 and 24 :

1 #include <iostream>
2 #include <string>
3 using namespace std;
4 
5 class MyClass{
6 	private :
7 		string first, second ;
8 
9 	public:
10		void set(string, string) ;
11		string getFirst() ;
12		string getSecond() ;
13 };
14
15 void MyClass::set(string x, string y){
16	first = x ;
17	second = y ;
18 }
19 
20 string MyClass::getFirst(){
21	return first;
22 }
23
24 string MyClass::getSecond(){
25	return second;
26 }
27
28 int main() {
29
30	MyClass objectA ;
31
32	objectA.set("Hello, ","World!") ;
33
34	cout << objectA.getFirst() << objectA.getSecond() << endl ;
35
36	return 0;
37 }

Compile and Run:

Hello, World!

Messages

Messages are the communication mechanism between objects.

Messages enable one object to invoke an action (method) in another object.

Messages comprise of three components:

  1. The object being addressed
  2. The method to perform
  3. Any parameters required by the method

Carry on with the previous example, the messages can be seen on line 32:

objectA.set("Hello, ", "World!");

and similarly on line 34 (without parameters):

1 #include <iostream>
2 #include <string>
3 using namespace std;
4  
5 class MyClass{
6	private :
7		string first, second ;
8 
9	public:
10		void set(string, string) ;
11		string getFirst() ;
12		string getSecond() ;
13 };
14 
15 void MyClass::set(string x, string y){
16	first = x ;
17	second = y ;
18 }
19 
20 string MyClass::getFirst(){
21	return first;
22 }
23 
24 string MyClass::getSecond(){
25	return second;
26 }
27 
28 int main() {
29 
30	MyClass objectA ;
31 
32	objectA.set("Hello, ","World!") ;
33 
34	cout << objectA.getFirst() << objectA.getSecond() << endl ;
35 
36	return 0;
37 } 

Compile and Run:

Hello, World!

Abstraction

Abstraction is the concept of focusing on the key elements of an item rather than the unimportant (i.e. pulling out [abstracting] the key features), whilst also hiding the way it's implemented.

For example, we all know a motorbike is made up of many objects, but essentially they all have two wheels, a frame, an engine, handle bars and a seat -- this is abstracting the main aspects of a motorbike. We don't particularly care how it works internally, as long as it does. We can then refine any particular instance of an object according to the specifics required, i.e. by way of defining sub-classes from super classes that add specific details required for the sub-class object.

Similarly, we can apply this concept to programming to create generic Abstract Data Types (or Abstract Base Classes) and call upon its methods for a specific object according to the (data) type of object.

This allows focus on the "What" not the "How".

The classic example is that of a polygon. We know that it is a shape that has sides and an area. We can declare some abstract information of the shape such as its height and width, and then further refine the shape according to the sub-class to define its area:

1 #include <iostream>
2 #include <string>
3 using namespace std;
4 
5 class Shape{
6	protected :
7 		int height, width;
8	public:
9		void set(int, int) ;
10 } ;
11 
12 class Rectangle : public Shape {
13	public:
14		int area() {
15			return (height * width) ;
16		}
17 } ;
18 
19 class Triangle : public Shape {
20 public:
21	int area() {
22		return (height * width) / 2 ;
23	}
24 } ;
25 
26 void Shape::set(int x, int y){
27	height = x ;
28	width = y ;
29 }
30 
31 int main() {
32 
33	Rectangle myRect ;
34	myRect.set(4,5) ;
35	cout << "Rectangle has an area of: " << myRect.area() << endl ;
36 
37	Triangle myTri ;
38	myTri.set(4,5) ;
39 
40	cout << "Triangle has an area of: " << myTri.area() << endl ;
41 
42	return 0;
43 }

Compile and Run

Rectangle has an area of: 20
Triangle has an area of: 10

Access Specifiers

The access specifiers define the level of visibility of a class's members to other objects.

The following keywords are used to define the level of access:

  • public
    • public members are accessible any place the object is visible
    • public methods should be the only way to change an object's attributes
    • public members make up an object's public interface
  • private
    • private members are accessible only from other members of the same class
      • i.e. once instantiated, only that object
  • protected
    • protected members are accessible from other members of the same class and to members of derived classes derived
      • i.e. a child class can also access the protected members of the parent

The access specifier is declared within a class's codeblock after its opening curly brace { by using one of the above keywords followed with a colon : All members following from that point forward are then considered to fall within the access specifier defined, up to the next access specifier or closing curly brace }

The default access specifier for a class is private, and can be omitted -- however, it's good programming practice to include for the sake of readability (if only for yourself at a future stage).

The general rule is to keep all of your data private and provide public methods to access it. This concept is known as data hiding.

public:

With all members defined public, an object's data can be changed without having to use its methods:

1 #include <iostream>
2 using namespace std ;
3 
4 class Triangle {
5 
6 public:
7	float width ;
8	float height ;
9 
10	//setters
11	void setWidth(float x){ width = x ; }
12	void setHeight(float y){ height = y ; }
13	//getters
14	float getWidth(){return width ; }
15	float getHeight() {return height; }
16 
17	//method
18	float area(){
19		return ((width * height) / 2) ;
20	}
21 } ;
22 
23 int main () {
24 
25	Triangle myTriangle ;
26 
27	myTriangle.setWidth(12) ;
28	myTriangle.setHeight(2000) ;
29	myTriangle.height = 10 ;
30 
31	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
32	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
33	cout << "myTriangle area: " << myTriangle.area() << endl ;
34 
35	return 0;
36 }

Compile and Run

myTriangle width was set at 12
myTriangle height was set at 10
myTriangle area: 60

Although the method was called on line 28 to set the height for myTriangle, it was possible to directly access the height on line 29 since all members (including the object's data on lines 7 and 8) are public.

private:

Now (correctly) defining the class's data as private, we can only access its data by using its methods:

1 #include <iostream>
2 using namespace std ;
3 
4 class Triangle {
5  
6 private:
7	float width ;
8	float height ;
9 
10 public:
11	//setters
12	void setWidth(float x){ width = x ; }
13	void setHeight(float y){ height = y ; }
14	//getters
15	float getWidth(){return width ; }
16	float getHeight() {return height; }
17 
18	//method
19	float area(){
20		return ((width * height) / 2) ;
21	}
22 } ;
23 
24 int main () {
25 
26	Triangle myTriangle ;
27 
28	myTriangle.setWidth(12) ;
29	myTriangle.setHeight(2000) ;
30 //	myTriangle.height = 10 ; // does not compile, since height is private
31 
32	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
33	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
34	cout << "myTriangle area: " << myTriangle.area() << endl ;
35 
36	return 0;
37 }

Compile and Run

myTriangle width was set at 12
myTriangle height was set at 2000
myTriangle area: 12000

Since the default access specifier level for a class is private, any member not explicitly defined within an access specifier is assumed private.

protected: 

Allows derived/child class access:

1 #include <iostream>
2 using namespace std ;
3  
4 class Shape {
5  
6 protected:
7 	float height ;
8 } ;
9 
10 class Triangle:Shape {  //if no access specifier is declared the default of 'private' is used
11 
12 private:
13	float width ;
14 
15 public:
16	//setters
17	void setWidth(float x){ width = x ; }
18	void setHeight(float y){ height = y ; }
19	//getters
20	float getWidth(){return width ; }
21	float getHeight() {return height; }
22 
23	//method
24	float area(){
25		return ((width * height) / 2) ;
26	}
27 } ;
28 
29 int main () {
30 
31	Triangle myTriangle ;
32 
33	myTriangle.setWidth(12) ;
34	myTriangle.setHeight(2000) ;
35 
36	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
37	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
38	cout << "myTriangle area: " << myTriangle.area() << endl ;
39 
40	return 0;
41 }

Compile and Run:

myTriangle width was set at 12
myTriangle height was set at 2000
myTriangle area: 12000

In this overly simplified example, the height attribute for the child Triangle class is derived from the parent Shape class in which the child is inheriting the protected height data attribute.

getters/setters

Getters and setters are the common names for what is more formally known as the Accessors and Mutators, respectively, which provide the methods to set and get values for an object.

Since we want to keep all data private to the object, we need specific methods defined to allow an object to control how its data is accessed.

The general approach is to prefix the method names with set / get as per their required functionality:

e.g.

setHeight()… //to set the height attribute
getHeight()… //to get the height attribute

Since the scope of data members is local to the class (i.e. within its curly braces {}), values can be assigned to them by passing in a parameter to a class's method specifically defined for this purpose. Assuming a float height ; private member has been declared, we can set its value as follows:

void setHeight(float myVar) {
    height = myVar ;
}

As we are simply setting a value and expect no return, we use the void data type for the method. It is then followed by the setHeight identifier for the method and the expected parameter data type and identifier to be used within the body. The function then simply assigns the passed in myVar variable to the previously declared private member variable height.

Similarly, to get a value, a method is defined that simply returns the desired value:

float getHeight(){
    return height ;
}

The data type of the expected return value is declared for the getter, which is then followed by the getHeight identifier for the method whose body simply returns that value.

Continuing with the previous examples, we have already seen the getter and setter methods being used:

1 #include <iostream>
2 using namespace std ;
3 
4 class Triangle {
5 
6 private:
7	float width ;
8	float height ;
9 
10 public:
11	//setters
12	void setWidth(float x){
13		width = x ; 
14	}
15	void setHeight(float y){
16		height = y ;
17	}
18	//getters
19	float getWidth(){
20		return width ;
21	}
22	float getHeight(){
23		return height;
24	}
25 
26	//method
27	float area(){
28		return ((width * height) / 2) ;
29	}
30 } ;
31 
32 int main () {
33 
34	Triangle myTriangle ;
35 
36	myTriangle.setWidth(12) ;
37	myTriangle.setHeight(2000) ;
38 
39	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
40	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
41	cout << "myTriangle area: " << myTriangle.area() << endl ;
42 
43	return 0;
44 }

Compile and Run:

myTriangle width was set at 12
myTriangle height was set at 2000
myTriangle area: 12000

methods

In OO parlance, the term method is used to denote a function within a class.

If a class 's methods were to become increasingly large it could make the code difficult to read, and it is therefore common practice to declare prototypes for the methods inline (i.e. within the class) and to then define the implementation of the methods outside of the class's body, to then be accessed using the :: scope resolution operator.

1 #include <iostream>
2 using namespace std ;
3  
4 class Triangle {
5  
6 private:
7 	float width ;
8	float height ;
9 
10 public:
11	void setWidth(float) ;  //setter prototype
12	void setHeight(float) ;
13	float getWidth() ;      //getter prototype
14	float getHeight() ;
15	float area() ;          //method prototype
16 
17 } ;
18 
19 void Triangle::setWidth(float x){ //REMEMBER TO DECLARE RETURN TYPE
20 	width = x ;
21 }
22 void Triangle::setHeight(float y){ //REMEMBER TO DECLARE RETURN TYPE
23 	height = y ;
24 }
25 float Triangle::getWidth(){        //REMEMBER TO DECLARE RETURN TYPE
26 	return width ;
27 }
28 float Triangle::getHeight(){       //REMEMBER TO DECLARE RETURN TYPE
29	return height ;
30 }
31 float Triangle::area(){            //REMEMBER TO DECLARE RETURN TYPE
32	return ((width * height) / 2) ;
33 }
34 
35 int main () {
36 
37	Triangle myTriangle ;
38 
39	myTriangle.setWidth(12) ;
40	myTriangle.setHeight(2000) ;
41 
42	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
43	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
44	cout << "myTriangle area: " << myTriangle.area() << endl ;
45 
46	return 0;
47 }

Compile and Run

myTriangle width was set at 12
myTriangle height was set at 2000
myTriangle area: 12000

Constructors

A constructor is a special type of class method that is always called when an object is instantiated.

Typically used to set initial values for an object.

A constructor has exactly the same name as the class but has no return type!

A constructor cannot be explicitly called. It is automatically called when an object is instantiated.

If no constructor is defined, the compiler will automatically provide one for you. This is similar to declaring to a primitive data type (e.g. an int or a char) whereby storage will be allocated but is not initialised.

The previous example now has a (inline) constructor included on line 11:

1 #include <iostream>
2 using namespace std ;
3  
4 class Triangle {
5  
6 private:
7 	float width ;
8	float height ;
9 
10 public:
11	Triangle(){ //constructor
12		width = 45.45 ;
13		height = 12.34 ;
14	} ;
15	void setWidth(float) ;
16	void setHeight(float) ;
17	float getWidth() ;
18	float getHeight() ;
19	float area() ;
20 } ;
21 
22 void Triangle::setWidth(float x){width = x ;}
23 void Triangle::setHeight(float y){height = y ;}
24 float Triangle::getWidth(){return width ;}
25 float Triangle::getHeight(){return height ;}
26 float Triangle::area(){return ((width * height) / 2) ;}
27 
28 int main () {
29 
30	Triangle myTriangle ;
31 
32	myTriangle.setWidth(12) ;
33	myTriangle.setHeight(2000) ;
34 
35	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
36	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
37	cout << "myTriangle area: " << myTriangle.area() << endl ;
38 
39	Triangle myDefault ;
40	cout << "myDefault width was set at " << myDefault.getWidth() << endl ;
41	cout << "myDefault height was set at " << myDefault.getHeight() << endl ;
42	cout << "myDefault area: " << myDefault.area() << endl ;
43 
44	return 0;
45 }

Compile and Run:

myTriangle width was set at 12
myTriangle height was set at 2000
myTriangle area: 12000
myTriangle width was set at 45.45
myTriangle height was set at 12.34
myTriangle area: 280.427

A new triangle instance called myDefault was declared on line 39. Notice that no values have been assigned and therefore the constructor has set the object's values to those specific in the class.

Here's the same code but with the constructor defined outside the class:

1 #include <iostream>
2 using namespace std ;
3  
4 class Triangle {
5  
6 private:
7	float width ;
8	float height ;
9 
10 public:
11	Triangle() ;
12	void setWidth(float) ;
13	void setHeight(float) ;
14	float getWidth() ;
15	float getHeight() ;
16	float area() ;
17 } ;
18 
19 Triangle::Triangle(){
20	width = 45.45 ;
21	height = 12.34 ;
22 }
23 void Triangle::setWidth(float x){width = x ;}
24 void Triangle::setHeight(float y){height = y ;}
25 float Triangle::getWidth(){return width ;}
26 float Triangle::getHeight(){return height ;}
27 float Triangle::area(){return ((width * height) / 2) ;}
28  
29 int main () {
30 
31	Triangle myTriangle ;
32 
33	myTriangle.setWidth(12) ;
34	myTriangle.setHeight(2000) ;
35 
36	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
37	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
38	cout << "myTriangle area: " << myTriangle.area() << endl ;
39 
40	Triangle myDefault ;
41	cout << "myDefault width was set at " << myDefault.getWidth() << endl ;
42	cout << "myDefault height was set at " << myDefault.getHeight() << endl ;
43	cout << "myDefault area: " << myDefault.area() << endl ;
44 
45	return 0;
46 }

Compile and Run:

myTriangle width was set at 12
myTriangle height was set at 2000
myTriangle area: 12000
myTriangle width was set at 45.45
myTriangle height was set at 12.34
myTriangle area: 280.427

Constructors with parameters

It is possible to have as many constructors as you like as long as their signatures are different, and are therefore being overloaded.

This allows your parameters to be set at instantiation, rather than a default set.

1 #include <iostream>
2 using namespace std ;
3  
4 class Triangle {
5  
6 private:
7	float width ;
8	float height ;
9 
10 public:
11	Triangle() ; //default constructor prototype
12 
13	Triangle(float x, float y){ //overloaded constructor
14		width = x;
15		height = y;
16	}
17 
18	void setWidth(float) ;
19	void setHeight(float) ;
20	float getWidth() ;
21	float getHeight() ;
22	float area() ;
23 } ;
24 
25 Triangle::Triangle(){ //default constructor definition
26	width = 45.45 ; 
27	height = 12.34 ;
28 }
29 void Triangle::setWidth(float x){width = x ;}
30 void Triangle::setHeight(float y){height = y ;}
31 float Triangle::getWidth(){return width ;}
32 float Triangle::getHeight(){return height ;}
33 float Triangle::area(){return ((width * height) / 2) ;}
34 
35 int main () {
36 
37	Triangle myDefault(22.22, 31.13) ;
38	cout << "myDefault width was set at " << myDefault.getWidth() << endl ;
39	cout << "myDefault height was set at " << myDefault.getHeight() << endl ;
40	cout << "myDefault area: " << myDefault.area() << endl ;
41 
42	return 0;
43 }

Compile and Run:

myTriangle width was set at 22.22
myTriangle height was set at 31.13
myTriangle area: 345.854

The default constructor could now be placed within the parametrised constructor to simplify:

1 #include <iostream>
2 using namespace std ;
3 
4 class Triangle {
5  
6 private:
7	float width ;
8	float height ;
9 
10 public:
11	Triangle(float x = 45.45, float y = 12.34){ //default constructor
12		width = x;
13		height = y;
14	}
15	void setWidth(float) ;
16	void setHeight(float) ;
17	float getWidth() ;
18	float getHeight() ;
19	float area() ;
20 } ;
21 
22 void Triangle::setWidth(float x){width = x ;}
23 void Triangle::setHeight(float y){height = y ;}
24 float Triangle::getWidth(){return width ;}
25 float Triangle::getHeight(){return height ;}
26 float Triangle::area(){return ((width * height) / 2) ;}
27  
28 int main () {
29 
30	Triangle myDefault(22.22, 31.13) ;
31	cout << "myDefault width was set at " << myDefault.getWidth() << endl ;
32	cout << "myDefault height was set at " << myDefault.getHeight() << endl ;
33	cout << "myDefault area: " << myDefault.area() << endl ;
34 
35	return 0;
36 }

Compile and Run:

myTriangle width was set at 22.22
myTriangle height was set at 31.13
myTriangle area: 345.854

Constructor Initialisation Lists

Members can also be initialised using initialisation lists.

The members to be initialised are defined after the signature of the constructor, which is followed by a colon : and then specifying the members in a comma separated list with the passed in parameter(s) from the signature making up the parameter for the member being initialised:

Triangle::Triangle(int x = 45.45, int y = 12.34) : width(x), height(y) {} ;

equivalent to:

Triangle::Triangle(int x = 45.45, int y = 12.34) {
    width = x ;
    height = y ;
} ;
1 #include <iostream>
2 using namespace std ;
3 
4 class Triangle {
5 
6 private:
7	float width ;
8	float height ;
9 
10 public:
11	Triangle(float, float) ; //constructor prototype
12	void setWidth(float) ;
13	void setHeight(float) ;
14	float getWidth() ;
15	float getHeight() ;
16	float area() ;
17 } ;
18 
19 //constructor with initialisation list
20 Triangle::Triangle(float x = 45.45, float y = 12.34): width(x), height(y) {} ;
21 
22 void Triangle::setWidth(float x){width = x ;}
23 void Triangle::setHeight(float y){height = y ;}
24 float Triangle::getWidth(){return width ;}
25 float Triangle::getHeight(){return height ;}
26 float Triangle::area(){return ((width * height) / 2) ;}
27 
28 int main () {
29 
30	Triangle myDefault ;
31	cout << "myTriangle width was set at " << myDefault.getWidth() << endl ;
32	cout << "myTriangle height was set at " << myDefault.getHeight() << endl ;
33	cout << "myTriangle area: " << myDefault.area() << endl ;
34 
35	Triangle myTriangle(16.73, 29.84) ;
36	cout << "myTriangle width was set at " << myTriangle.getWidth() << endl ;
37	cout << "myTriangle height was set at " << myTriangle.getHeight() << endl ;
38	cout << "myTriangle area: " << myTriangle.area() << endl ;
39 
40	return 0;
41 }

Compile and Run:

myTriangle width was set at 45.45
myTriangle height was set at 12.34
myTriangle area: 280.427
myTriangle width was set at 16.73
myTriangle height was set at 29.84
myTriangle area: 249.612

Destructors

A destructor is another special class method, complimentary to a constructor, that cleans up resources by deleting the contents in the storage used for an object when it goes out of scope, or when the delete keyword is used on an object.

Has the same name as the class, preceded by a tilde ~
Has no return data type.
Takes no arguments.

Cannot be explicitly called. It is automatically called when the object goes out of scope.

If no destructor is defined, the compiler will automatically provide one for you. However, there might be time when you want to ensure the object has been cleaned, or you might want to carry out a quick exit task such as leaving a message.

1 #include <iostream>
2 using namespace std ;
3 
4 class SingleValue{
5 
6 private:
7	int myVar;
8 
9 public:
10	SingleValue() ; //constructor prototype
11 
12	~SingleValue() { //destructor
13		cout << "See ya later..." << endl ;
14	}
15 
16	void setValue(int) ;
17	float getValue() ;
18 } ;
19  
20 SingleValue::SingleValue(){ //constructor
21	myVar = 0 ;
22	cout << "Hello, World!" << endl ;
23 }
24 
25 void SingleValue::setValue(int x){myVar = x ;}
26 float SingleValue::getValue(){return myVar ;}
27 
28 int main () {
29 
30	SingleValue myValue ;
31 
32	myValue.setValue(42) ;
33 34 cout << "myVar = " << myValue.getValue() << endl ; 35 36 return 0; 37 }

Compile and Run:

Hello, World!
myVar = 42
See ya later

Source: Derrick Robinson, http://intcpp.tech-academy.co.uk/
Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License.

Last modified: Monday, November 16, 2020, 4:55 PM