Data structures and classes

Fundamentals on Computing for Robotics, Graphics and Computer Vision

Darío Suárez - Adolfo Muñoz

Data structure

Group of data elements (members) of potentially different types grouped together under one name

Data structure


			struct DataType { 
				member_type_01 member01; 
				member_type_02 member02; 
				member_type_03 member03; 
				...
			} data_variable1, data_variable2;
		

Data structure


			struct DataType { 
				member_type_01 member01; 
				member_type_02 member02; 
				member_type_03 member03; 
				...
			};
			DataType data_variable1;
			DataType data_variable2;
		

Designing data structures

  • Data structure should represent an entity with semantics
  • Members should aslo have a meaning
  • In general, avoid functional dependencies between members

struct specification


			struct Car {
				string brand;
				string model;
				int year;
			};
		

struct usage

struct usage (pointers)

Designing data structures

  • Data structures enable some abstraction
  • If a data structure can only be accessed through functions, it can be used regardless of its implementation

vectorint.h

vectorint.cpp

main.cpp

Designing data structures

  • Data structures can include members of other data structures
  • Data structures can include members that are pointers to themselves (recursive structures)

listint.h

listint.cpp

main.cpp

Data abstraction


		struct Rational { int num, den; };
		Rational create(int n, int d);
		Rational simplify(const Rational& r);
		Rational add(const Rational& r1, const Rational& r2);  
		

Object Oriented Programming = OOP

Abstract typeClass
Type and variable

						struct String { ... };
						...
						String str;
					
Class and object

						class String { ... };
						...
						String str;
					
Functions

						l = length(str);
						clear(str);
					
Methods (messages)

						l = str.length();
						str.clear();
					
Function parameters

						fill(str,16,'x');
						fill(str,4,'o');
					
Method parameters

						str.fill(16,'x');
						str.fill(4,'o');
					

Are we just doing the same thing and just changing the syntax?


YES

(for now)

Classes

A class consists on attributes and methods (or member functions)

Classes


			class Class {
				typeA1 attribute1;
				typeA2 attribute2;
				...
				typeM1 method(parameters) {
					implementation;
				}
			}; 
			

Classes

A class without methods is identical to a struct.

			class Class {
				typeA1 attribute1;
				typeA2 attribute2;
			}; 
			
Abstract typeClass

					struct String { 
						int size;
						char text[256]; 
					};

					void fill(String& str, int count, char c) {
						str.size = count;
						for (int i = 0; i < count; ++i)
							str.text[i] = c; 
					} 
					...
					String s;
					fill(s,16,'x');
				

					class String { 
						int size;
						char text[256]; 

						void fill(int count, char c) {
							this->size = count;
							for (int i = 0; i < count; ++i)
								this->text[i] = c; 
							} 
					};
					...
					String s;
					s.fill(16,'x');
				
this can be omitted if there are no ambiguities.

				class String { 
					int size;
					char text[256]; 

					void fill(int count, char c) {
						this->size = count;
						for (int i = 0; i < count; ++i)
							this->text[i] = c; 
						} 
				};
				

					class String { 
						int size;
						char text[256]; 
	
						void fill(int count, char c) {
							size = count;
							for (int i = 0; i < count; ++i)
								text[i] = c; 
							} 
					};
				

Visibility

  • private: Cannot access except from within the class
  • public: Can access from everywhere

Usually: private attributes and public methods

Visibility


			class String { 
			private:
				int size;
				char text[256]; 
			public:
				void fill(int count, char c) {
					size = count;
					for (int i = 0; i < count; ++i)
						text[i] = c; 
					} 
			};
		

Constructors

Methods that define operations executed when creating an object

Constructors: for setting up default attribute values.


			class Complex { 
			private:
				float _real, _imag; 
			public:
				Complex() {
					_real = _imag = 0;
				} 
			};
		

			Complex c; 
			// c._real = 0; c._image = 0;
			Complex* pc = new Complex;
			// pc->_real = 0; pc->_imag = 0;
		

Constructors: for setting up parametrized attribute values regardless of visibility.


			class Complex { 
			private:
				float _real, _imag; 
			public:
				Complex(float real, float imag) {
					_real = real; _imag = imag;
				} 
			};
		

			// Complex c;  Complex* pc = new Complex <-- Can't do these
			Complex c(1,0); 
			//c._real=1; c._imag=0;
			Complex* pc = new Complex(1,0);
			// pc->_real = 1; pc->_imag = 0;
		

What happens when using classes as attributes?


			class ElectromagneticWave {
			private:
				Complex phasor_vertical, phasor_horizontal;
			public:
				ElectromagneticWave() {
					phasor_vertical = Complex(0,-1);
					phasor_horizontal = Complex(1,0);
				} 
			} 
		

Does not compile if Complex() does not exist (needs to construct attributes)

What happens when using classes as attributes?


			class ElectromagneticWave {
			private:
				Complex phasor_vertical, phasor_horizontal;
			public:
				ElectromagneticWave() :
					phasor_vertical(0,-1), phasor_horizontal(1,0) {} 
		

It actually invokes the constructores.

Constructors: more versatile with default parameter values.


			class Complex { 
			private:
				float _real, _imag; 
			public:
				Complex(float real = 0, float imag = 0) {
					_real = real; _imag = imag;
				} 
			};
		

			Complex c1; // c1._real=0; c._imag=0;
			Complex c2(1,1); // c2._real=1; c2._imag=1;
			Complex c3(-1);  // c3._real=-1; c3._imag=0;
			Complex c4 = 2;  // c4._real=2; c4._imag=0;
		

Constructors: can be used to reserve resources (such as memory)


			class VectorInt { 
			private:
				int* data;
				int size;
			public:
				VectorInt(int s) {
					size = s; data = new int[s]; 
				} 
			};
		

		{		
			VectorInt vi(128);
			...
		}	
		

What about freeing that memory?

Destructors

Methods that define operations executed when object dissappears from memory

Destructors


			class VectorInt { 
			private:
				int* data;
				int size;
			public:
				VectorInt(int s) {
					size = s; data = new int[s]; 
				} 
			};
		

Destructors


			class VectorInt { 
			private:
				int* data;
				int size;
			public:
				VectorInt(int s) {
					size = s; data = new int[s]; 
				} 
				~VectorInt() {
					delete[] data; 
				} 	
			};
		

		{		
			VectorInt vi(128);
			...
		} // vi dissappears here
		

The data is now deleted seamlessly

Operator overloading

Methods with special names are interpreted as operators.

Operators: can be defined as methods with special names


			class Complex { 
			private:
				float _real, _imag; 
			public:
				Complex(float real = 0, float imag = 0) {
					_real = real; _imag = imag;
				} 
				Complex operator+(const Complex& that) const {
					return Complex(this->_real+that._real,this->_image+that._image);
				} 
			};
		

Operators: some of them can only be functions

Operators: some of them can only be methods


			class VectorInt { 
			private:
				int* data;
				int size;
			public:
				VectorInt(int s) {
					size = s; data = new int[s]; 
				} 
				~VectorInt() {
					delete[] data; 
				} 	
				int& operator[](int i) { return data[i]; }  
				int operator[](int i) const { return data[i]; }  
			};
		

Class code distribution

It is still a good idea to separate specification from implementation

vectorint.h

vectorint.cpp

main.cpp