College Courses


WeekDatesTopic / ActivityLinks / Material
Week 13/1, 4/1, 5/1Intro+Logistics, Recap of C, C and C++Slides-1 ,Slides-2 ,Slides-3
Week 210/1, 11/1, 12/1Constants and inline functions, Reference and pointers, Default Parameters & Function Overloading, Operator overloadingSlides-1 ,Slides-2 ,Slides-3 ,Slides-4
Week 317/1, 18/1, 19/1Dynamic Memory Management, Classes and objects, Access specifiersSlides-1 ,Slides-2 ,Slides-3
Week 424/1, 25/1Constructor, destructor, object lifetime, Copy Constructor and Copy Assignment Operator, Const-nessSlides-1 ,Slides-2 ,Slides-3
Week 531/1, 1/2, 2/2Static Members, Friend Function and friend Class, Operator overloading for user defined typesSlides-1 ,Slides-2 ,Slides-3
Week 67/2, 8/2, 9/2Operator overloading, Namespaces, InheritenceSlides-1 ,Slides-2 ,Slides-3 ,Slides-4 ,Slides-5
Week 728/2, 1/3, 2/3Inheritence (Example + Private/Protected), Polymorphism (Type casting + Static / Dynamic Binding + Pure Virtual Function), Example Program (Slides 6,7)Slides-1 ,Slides-2 ,Slides-3 ,Slides-4 ,Slides-5 ,Slides-6 ,Slides-7
Week 85/3, 6/3, 7/3Virtual Function Table, Type Casting (const_cast,static_cast,reinterpret_cast,dynamic_cast), ExceptionsSlides-1 ,Slides-2 ,Slides-3 ,Slides-4 ,Slides-5 ,Slides-6
Week 914/3, 15/3Exceptions(Contd.), Function Templates, Class templates, FunctorsSlides-1 ,Slides-2 ,Slides-3 ,Slides-4
Week 1020/3, 21/3, 22/3SDLC: Goals, Benefits, Stages, Models - waterfall, v-shaped, Spiral, Agile, UML DiagramsSlides-SDLC ,Slides-UML ,Slides-Use case diagram ,Slides-class diagram
Week 1127/3, 28/3Software TestingSlides-Testing

References:

  • Roger S Pressman, Software Engineering: A Practitioner’s Approach, 7th Edition, McGraw Hill Education,2009.
  • Rajib Mall, Fundamentals of Software Engineering, Prentice Hall India, 2014
  • Bjarne Stroustrup, The C++ Programming Language, 4th Edition, Addison-Wesley, 2013
  • Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison Wesley, 1994

Prep

  • Software Engineering

Index

  • vectors and strings and shit
  • Constants and inline functions
    • const, #define
    • const with pointer
    • read-only methods
    • volatile
    • inline functions vs macros with parameters
  • Reference and pointers
    • return by reference
  • Default Parameters & Function Overloading
    • overload resolution
  • Operator overloading
  • Dynamic Memory Management
  • Classes and objects
  • Access specifiers
  • Constructors/Destructors/Lifetime, Copy, Constness

const

promise that you won’t change a variable

const int n; // compilation error since n must be initialised

weird example

#include <iostream>
using namespace std;
 
int main() {
	const int a = 5; // const variable
	int* b; // normal pointer
	b = (int*) &a; // this is allowed
	*b = 10; // this is allowed apparently
	count << a << " " << b << " " << &a << " " << *b << endl;
}
5 0xdeadbeef 0xdeadbeef 10

b actually points to a. But when accessed through a the compiler substitutes the constant expression. Technically the behavior is undefined

with pointers:

  1. int* a normal. can take address/value of anything, including constant variables
  2. const int* a. Value of a is constant. can’t change by dereferencing it, can change address though
    1. *a = 2 ERROR
    2. a = (int*) &NEW_VARIABLE WORKS
  3. int* const a does the opposite of above. can change the value at a, but not a itself
  4. int const* a is the same as const int* a
  5. const int* const a makes everything constant

this directly applies to strings as well, where you may change the string but not individual characters and vice versa

char *str = strdup("IIT Kharagpur");
str[0] = 'N';
str = strdup("MeowLand");
 
const char *str; // can change str but not str[i]
char* const str; // can change str[i] but not str
const char* const str; // can not change anything

with classes

class Entity {
private:
	int m_X, m_Y,
public: 
	// adding const after parameters says the method can't do anything to the class. 
	// It is essentially read only
	int GetX() const { 
		return m_X;
	}
}

Note

int* x, y; // only x is a pointer
int *x, *y; // both are pointers

volatile

allows other operations to change your variable. shared memory

https://stackoverflow.com/questions/58252099/understanding-the-volatile-keyword-in-c

volatile int* pi1 = 0; // value at p is volatile
int* volatile pi2 = 0; // address of p is volatile
volatile int* volatile pi3 = 0; // both are volatile

volatile removes a lot of compiler optimisations

volatile x = 1;
// ...
x++;
  • how this would work is a three step process usually
    • mv <reg>, x
    • add <reg>, 0x01
    • mv x, <reg>
  • however what if there is an interrupt during this? so you want to protect your x. you’ll be doing something like disabling interrupt or something. C doesn’t know anything about multithreading so no inbuilt support.

inline functions

functions that are expanded right below where they are called. This creates a speed vs memory tradeoff if the inline function is called multiple times

func1 <---- jump here when called
// have to pass parameters to this location // creates overhead
inline func2 
...
main
call func1
call func2 
func2 <--- func2 is expanded here, so less speed overhead
#include <iostream>
using namespace std;
 
inline int SQUARE(int x) { return x*x; }
 
int main() {
	int a = 3, b;
	b = SQUARE(a);
	cout << b << endl;
	return 0;
}
0000000000001149 <main>:
    1149:	55                   	push   %rbp
    114a:	48 89 e5             	mov    %rsp,%rbp
    114d:	48 83 ec 10          	sub    $0x10,%rsp
    1151:	c7 45 f8 03 00 00 00 	movl   $0x3,-0x8(%rbp)
    1158:	8b 45 f8             	mov    -0x8(%rbp),%eax
    115b:	89 c7                	mov    %eax,%edi
    115d:	e8 30 00 00 00       	call   1192 <_Z6SQUAREi> // CALL SQUARE
    1162:	89 45 fc             	mov    %eax,-0x4(%rbp)
    1165:	8b 45 fc             	mov    -0x4(%rbp),%eax
    1168:	89 c6                	mov    %eax,%esi
    116a:	48 8d 05 cf 2e 00 00 	lea    0x2ecf(%rip),%rax        # 4040 <_ZSt4cout@GLIBCXX_3.4>
    1171:	48 89 c7             	mov    %rax,%rdi
    1174:	e8 c7 fe ff ff       	call   1040 <_ZNSolsEi@plt>
    1179:	48 8b 15 40 2e 00 00 	mov    0x2e40(%rip),%rdx        # 3fc0 <_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4>
    1180:	48 89 d6             	mov    %rdx,%rsi
    1183:	48 89 c7             	mov    %rax,%rdi
    1186:	e8 a5 fe ff ff       	call   1030 <_ZNSolsEPFRSoS_E@plt>
    118b:	b8 00 00 00 00       	mov    $0x0,%eax
    1190:	c9                   	leave
    1191:	c3                   	ret

0000000000001192 <_Z6SQUAREi>: // SQUARE
    1192:	55                   	push   %rbp
    1193:	48 89 e5             	mov    %rsp,%rbp
    1196:	89 7d fc             	mov    %edi,-0x4(%rbp)
    1199:	8b 45 fc             	mov    -0x4(%rbp),%eax
    119c:	0f af c0             	imul   %eax,%eax
    119f:	5d                   	pop    %rbp
    11a0:	c3                   	ret

you can see that SQUARE() (0x1192) was expanded right after main() (0x1149) which is considerably closer than it would be normally with _start() and all cluttering up the stack

Warn

  • inlineing is a directive, the compiler is suggested to inline, not forced to. It may not inline functions with a large body.
  • inline functions may NOT be recursive
  • the function body is needed for inlineing at the time of function call, which means that you can not put them in libraries etc where they are treated like extern. Which is why implement inline functions in header files as the CPP expands header files in the main file.
  • inline functions can not be overloaded. They must not have two different definitions (unless they are the exact same definition)

Pointers

#include <iostream>
using namespace std;
 
int main() {
	unsigned char* buffer = new char[8];
	memset(buffer, 0, 8); // i liked this, the rest of the example is useless
	delete[] buffer;
}

References

pointers in disguise

references have to reference an already existing variable

  • they don’t occupy memory
#include <iostream>
 
using namespace std;
 
inline void increment(int value) { value++; }
inline void ptrIncrement(int* value) { (*value)++; }
inline void refIncrement(int& value) { value++; }
 
int main() {
	int a = 5; // variable
	int* b = &a; // pointer
	int& c = a; // reference, must be initiliased
 
	// c is now basically an alias for a
	c = 2; // this works
 
	increment(a); // passed by value => a NOT incremented
	cout << a << endl; // still 2
	ptrIncrement(b); // passed by reference => a is incremented
	cout << a << endl; // 3
	refIncrement(c); // also passed by reference, but simpler
	// can also pass a directly
	cout << a << endl; // 4
 
	int d = 0;
	c = d; // a = 0
	// can NOT change what c references
 
	cout << a << endl; // 0
}

using const int& stops a reference parameters from being changed in the function. But this is essentially the same as pass by value, except it saves memory

https://stackoverflow.com/questions/270408/is-it-better-in-c-to-pass-by-value-or-pass-by-reference-to-const

https://drdobbs.com/move-constructors/184403855

however it is slower because pointer traversal has speed overhead

Return by Reference: TBA

• Call ◦ Pass parameters of built-in types by value ▷ Recall: Array parameters are passed by reference in C and C++ ◦ Pass parameters of user-defined types by reference ▷ Make a reference parameter const if it is not used for output • Return ◦ Return built-in types by value ◦ Return user-defined types by reference ▷ Return value is not copied back ▷ May be faster than returning a value ▷ Beware: Calling function can change returned object ▷ Never return a local variables by reference

Default Parameters

#include <iostream>
using namespace std;
 
inline IdentifyFunc(int a = 10) { return (a); } // func with default parameters
 
int main() {
	int x = 5; y;
	y = IdentityFunc(x); // y = 5
	y = IdentityFunc(); // y takes default = 10
}

this allows some parameters to be optional

  • all parameters to the right of a default parameter must have default values
    void f(int, double = 0.0, char*) // ERROR
  • default parameters can not be redefined
    void g(int = 0);
    void g(int = 69); // ERROR
- Default parameters should be supplied in the header files, and not in the function definitions
	```cpp
	------- myFunc.h
	void g(int, double, char = 'a') 
	void g(int i, double f = 0.0, char ch); // new overload
	void g(int i = 0; double f; char ch); // new overload
	------- myFunc.c
	import "myFunc.h"
	using namespace std;

	// do not add defaults here
	void g(int i, double d, char c) {
		// ...
	}	
	-------

Function Overloading

Functions having the same name, similar functionality, but different algorithms, are identified by different interfaces (parameters).

You can call the same function with different parameters to do different things

typedef struct { int data[10][10]; } Mat; // 2D Matrix
typedef struct { int data[1][10]; } VecRow; // Row Vector
typedef struct { int data[10][1]; } VecCol; // Column Vector
 
void Multiply(const Mat& a, const Mat& b, Mat& c); // c = a * b
void Multiply(const Mat& a, const VecCol& b, VecCol& c); // c = a * b
void Multiply(const VecRow& a, const Mat& b, VecRow& c); // c = a * b
void Multiply(const VecCol& a, const VecRow& b, Mat& c); // c = a * b
void Multiply(const VecRow& a, const VecCol& b, int& c); // c = a * b
 
int main() {
	Mat m1, m2, rm; VecRow rv, rrv; VecCol cv, rcv; int r;
	Multiply(m1, m2, rm); // rm <-- m1 * m2
	Multiply(m1, cv, rcv); // rcv <-- m1 * cv
	Multiply(rv, m2, rrv); // rrv <-- rv * m2
	Multiply(cv, rv, rm); // rm <-- cv * rv
	Multiply(rv, cv, r); // r <-- rv * cv
	return 0;
}

This is also called Static Polymorphism

another example

#include <iostream>
using namespace std;
 
int Area(int a, int b) { return a*b; }
int Area(int c) {return c*c; }
double Area(double a, double b) { return a*b; }
  • two functions having the same signature but different return types can not be overloaded (obv)

    int Area(int a, int b);
    double Area(int a, int b);

**Overload Resolution**:
This is theoretical and conceptual: Must study
- https://www.youtube.com/watch?v=zVJfwYtjIoY
- https://learn.microsoft.com/en-us/cpp/cpp/function-overloading?view=msvc-170


# Operator Overloading

```cpp
#include <iostream>
#include <string>

struct Vector2 {
	float x, y;
	
	Vector2(float x, float y)
		: x(x), y(y) {}
	
	Vector2 Add (const Vector2& other) const {
		return Vector2(x + other.x, y + other.y);
	}

	Vector2 Multiply (const Vector2& other) const {
		return Vector2(x* other.x, y * other.y);
	}

	Vector2 operator+(const Vector2& other) const {
		return Add(other);
	}

	Vector2 operator*(const Vector2& other) const {
		return Multiply(other);
	}
};

int main() {
	Vector2 position(4.0f, 4.0f);
	Vetor2 speed(0.5f, 1.5f);
	Vector2 powerup(1.1f, 1.1f);

	Vector2 result = position.Add(speed.Multiply(powerup));
	// getting convoluted now, define operators instead
	result = position + (speed * powerup); // do this instead
}

0 items under this folder.