Beruflich Dokumente
Kultur Dokumente
-c++ is middle level language because both procedural (low level) and OO (high l
evel)
-compiles to machine code
-class is described by declaration, in ClassName.h, and definition, in ClassName
.cpp
-declaration: declares name for class, class's members (functions protot
ypes and data members) and their visibility -> ENDS IN SEMICOLON
#ifndef CLASS_NAME_H
#define CLASS_NAME_H
class ClassName {
public: ClassName();
protected:
private:
}; // <---------------#endif
-definition: contains implementation of function prototypes
#include "ClassName.h"
ClassName() {
}
-pointer have two pieces of info, memory address and type (or void) of o
bject pointed to
-& translates item to reference,
i.e. b gets address of variable a: int a =5, int * b=&a;
-* dereferences pointer to access item stored at location of memory
-Note: Circle * myCircle=new Circle(5);
//*myCircle.area(); is wrong, (*myCircle.area()); is wrong, (*my
Circle).area() is right, but the best is
myCircle->area();
-c++ files compiled one at a time (unlike java), so classes must be declared bef
ore used
-thus, class declarations can be seperated from implementation in .h fil
e and then included using compiler directive:
#include "className.h"
-treats .h file as if were in source code where #include stateme
nt is
-we seperate files because in large projects, many files use same class
-includes can accumulate (if you include a file that includes other files you ge
t them all), so only include files you need
-Include guard: used to ensure we don'y unintentionally include more than one de
claration per class
i.e.
#ifndef CLASS_NAME_H
#define CLASS_NAME_H
class ClassName {
};
#endif
-The class declaration (inside Class { };), gives scope for labels (variables an
d function names)
-once outside of class we need to specify we want to use it (i.e. in cpp
) by going ClassName::FunctionName() {}
i.e. Circle::Circle(double radius) {
this->radius = radius;
}
-We can create arbitrary scope using namesapaces, and access variables of namesp
ace by either double colons or by declaring that you are "using" specific namesp
ace
{}int&
reieturn
f ( xmax(int
lse
> y ) &x, int &y)
x;
y;
Func Call: int a=3, b=5;
cout << max(a,b) << endl;
-NOTE
MyClass * obj1=new MyClass(); // pointer on stack to object on heap
MyClass obj2(): // Object on call stack
MyClass * ob3=&obj2; pointer to object on call stack
-can point from stack to heap, or stack to stack in earlier frames i.e. passing
by reference
-no pointer should point to object in later call frame (possible
when returning pointers), or from heap to stack
-thus, object can be local variables when object is only used within function, p
ointers to object passed to other functions as parameters, and no pointer to obj
ect is returns or given to heap objects
-variable should be on heap when pointing from object to other object on
heap, or when we want to pass back object as return value
2.2
-standard c++ library introduces string class in string library
-#include <string>
-intializing strings (if using namespace std; or using std::string;
string str1("Hello World");
string sr2= "Hi There!";
string str3(5,'*'); <- 5 asterisks in a row
-to copy string: string str; string str2("SUP");
str.assign("hi"); // str now stores hi
str.assign(str2); //str stores sup
-concatenating strings: string str1; string str2("man");
str1.append(str2); // str1="man"
str1.append(80,'*'); // str1=man*** //77 more *
-accessing individual characters
str.at(index);
-computing string length:
str.length();
-c++ allows operators to be overloaded, string library makes heavy use of operat
or overloading
i.e. oneString.assign(another) <-> oneString=another;
oneString.append(another) <-> onestring+=another;
oneString.at(n);
<-> oneString[n];
also if(str1 < str2) or >, >=, <=, ==
-i/o in c++ occurs in "streams"
-stream= sequence of bytes of indefinite length
-input: bytes flow from device into main memory
-output: bytes flow from main memory to a device
-<< : stream insertion operator, write data to stream
->> : stream extraction operator, write data from stream
-defined for all standard c++ data types, and can be overloaded
to work with our classes
-std::cin: standard input stream, std::cout : standard output stream, std::err :
standard error stream, std::clog: buffered error stream
--<< >> are left associative and so can be chained
-standard input and output is included in iostream library
-#include <iostream>
std::string name;
std::cout << "Type name: ";
-can't rely on compiler to initialize values (i.e. default value of any time cha
nges from machine to machine)
-constructor called when object of class created
-allows one to gaurantee member variables of new data type always initia
lized properly
-should initialize all members of class in constructor, i.e. primitive types get
meaningful value, objects call appropriate constructor, and pointers assigned a
t meaningful address with entity initialized at address
-default constructor: constructor with no arguments
-generated by compiler if no constructors are defined
-default constructs base class, default constructs any object me
mbers, performs no other initializations
-when executing constructor, before entering code of constructor, already create
s space for members and calls constructors for member objects
-thus will call default constructors, and if initailized inside construc
tor, then reinitialize any object values inside constructor
-solve problem by initializization list allowing us to specify which con
structors to use when creating object
syntax (in .cpp file) ClassName::ClassName(varOneType nameOne, varTwoType nameTw
o) : _varOneName(nameOne), _varTwoName(nameTwo) {
//rest of constructor
}
i.e. Person::Person(string name, string pet_name) : _name(name), _pet(pet_name)
{}
-destructor called when object destroyed and reclaims ddynamically allocated mem
ory and release resources (close files, database connections, etc.)
-called when variable holding object goes out of scope, or when delete c
alled on pointer to object
-cannot be overloaded
-syntax in .h file: ~ClassName(); in .cpp file: ClassName::~ClassName() {//conte
nts }
-when members of class destroyed, primitive type members' space reclaimed implic
itly following destructor, object type members' space reclaimed implicitly follo
wing destructor (each objects' destructor called implicitly), space for pointers
must be reclaimed because space reclaimed for pointer only
-if destructor not defined for class, compiler implicitly defines it as empty, w
hich still correctly reclaims memory for primitive and object members, but will
not delete pointer referenced data
-when new is called, space allocated on heap for data and constructor called
-when delete is called, destructor called and space reclaimed
-any data allocated with new, should be reclaimed with delete
-any data allocated with new[] should be reclaimed with delete[]
-delete[] only deletes space allocated for array and does not de
lete array elements
-general rule: if new called in constructor, should call delete
in destructor
-copy constructor called when creating an object by copy an EXISITNG object
i.e. Person p1("Jeff"); Person p2=p1; // copy constructor Person p3(p1); //copy
constructor
-called when passing object as parameter by value, or when returning by
value
i.e. void f(Person p) //calls copy constructor on Person P
{ return p; }// p copied again when returned by value
-syntax of copy constructor:
ClassName::ClassName(const ClassName& other) {..}
i.e. Person::Person(const &Person other) _name(other._name), _bff(other._bff) {}
-parameter must be reference and must be const (so we cannot change obje
ct)
ucture
-can do iterator arithmetic just like pointer arithmetic
i.e. reverse(v.begin()+1,v.end()-1);
-iterator supports dereference and pointer operator to access value curr
ently pointed at by operator
-obviously used for iterating
i.e. std::vector<string> v;
v.push_back("hello"); v.push_back("world");
for(std::vector<string>::iterator it = v.begin(); it!=v.end(); ++it) {
cout << (*it) << endl;
cout << it->length() >> endl;
}
Lecture 5- const correctness
-const: keyword specifying that data should not be modified
-both pointers and data can be const, so use right to left rule
-note * goes to right of pointers and left of type
int* const * b // pointer to a constant pointer to an integer
const int* const * const d // constant pointer to constant pointer to constant i
nteger
-cannot assign constant data to a pointer to non constant data, also cannot cons
tant pointer to nonconstant pointer
i.e. const char * h = " Hello ";
char* w=World;
h[1]='u'; does not compile because const data
h=w; // compiles because non constant pointer
char* const h="Hello";
char* w="World";
h[1]='u'; //compiles because nonconst data
h=w; // does not compile because pointer is constant
-we can assign address of non-const object to const pointer, (we promise not to
change something that is ok to change)
i.e. i=4;
const int* j=&i; //this is fine!
-we cannot assign address of const object to nonconst pointer though
const int i=4;
int* j=&i; //compilation error
-string literals like "hello" are technically a const char* but we can assign it
to a char* (this is an exception to the general rule)
-in function declaration const can refer to return value, paramater, or function
as whole
-const data returned by value can be assigned to non const variable beca
use we are simply copying return values into variable, not taking variable itsel
f
-so for built in types, pointless to declare them as const becau
se cannot be used as lvalue anayways i.e. sum(3,4)=5 //error
-good idea for user defined types to be returned by value becaus
e assignments like the one below are legal if return value is not const
i.e.const
const
Rational
(a
}{...
return
* b)Rational
a=+a,c;
Rational
b;b,//c;
&assign
rhs);
operator
to the*(product
const Rational
of a * bconst
& lhs int
, sum(int a, int b)
int i= sum(3,4);
-data returned by pointer or reference should almost always be returns a
s const data
ie. Person
string
& name
( string
() { return
name )_name
: _name
; }( name ) { }
allows for
Person
p.
namep("
() =Jeff
"Joe";
");
-so this is much better: const string& name() { return _name ; }
-first choice for paramater should be const reference because efficient (no copy
ing), syntax is identical to passing by value, and passing const means we cannot
change referenced object
-also allows us to accept temporaries,i.e. "hello", because temporaries
always const
}{ie.void
cout << name
printName
<< endl
( string
;
& name )
printName ("Joe"); // compilation error !
-so this is much better: void printName ( const string & name );
-we methods are created in a class, compiler inserts a 'constant pointer to this
' as first parameter in methods signature so
{class
};
const string
Person & name ();
compiles to
{class
};
const string
Person & name ( Person * const this );
-when we call method on object, compiler silently passes pointer to object as f
irst parameter
i.e. Person p;
p.name(); -> compiles to name(&p);
-if we declare method to be const, that causes this to be const
-thus, specifies that we cannot make changes to state of reciever in met
hod (i.e. this->name="manor; would generate error in const method)
i.e. const string & name () const ; compiles to -> const string& name(const Pers
on* const this);
-also means that we cannot call non-const methods within method on "this
" regardless of whether methods actually change reciever
-if method is declared const, then reference and pointer types returned must be
declared const
-two definitions of const:
-bitwise constness: does not modify bits of object
-conceptual constness: can modify object, but only in ways undetectable
to clients
-c++ implements bitwise constness
-methods differing only in their constness can be overloaded
-can use mutable keyword for bitwise constness, by declaring data member
s mutable -> they can be changed in const methods
i.e. mutable int _length;
-by overloading[] operator, const and nonconst strings handled differently
-if pointer of reference param is not modified - should be declared const, if po
inter of reference member returned - should be const, if function does not chang
e member data should be const
Lecture 6
-benefits of inheritance: reusability, extensibility (add functionality), polymo
rphism (write generic code handling multiple types)
-syntax
class Person{}
class Student : public Person {} // DONT FORGET PUBLIC
-if Person has constructors:
{Person
}Person (()const string & name ) : _name ( name )
and Student has
{:Student
} Person(name),
( const _number
string &(name
number
, const
)
string & number )
-default constructor in person called when instantiating new student
-so must call specific superclass constructor in initialization list
{:Student
} _number( (const
numbephotor
string &)name , const string & number )
-if there is no default constructor in superclass, and forget to call sp
ecific constructor in initialization list of subclass, you get an error
omething
-if data
-if data
-if data
of our
member
member
member
-if access
ss
-if access
protected
-if access
ase class
specifier is public, all data members remain as they are in super cla
specifier is protected, then all data members in baseclass are either
or private
specified is private, all data members in base class are private in b
-syntax: const_char<type>(varName);
i.e. const char* str="Hello World";
printstring(str); //doesn't work because parameter is non const
printstring(const_cast<char*>(str));
-static_cast is similar to c-style but safer
-syntax: static_cast<type>(varName);
i.e. float f= static_cast<float>(i);
-allows down casting, but not upcasting
-dynamic cast used to safely convert pointer/references up and down inheritance
hierarchy
-only works with polymorphic types (at least one method in source type v
irtual)
-works by checking run-time infoo stored in vtable of object
-object only has vtable if has virtual method, so only works on
classes with at least one virtual method
-i.e. Class Person{}; class Student : public Person {}; class Employee:
public Person(){};
41 Student
42
Person **p1s1==new
dynamic_cast
Person (" <JoeStudent
"); *>( p1); // s1 == NULL because Person s
tored in pointer
Student
53
54
55 Person
Student
* *s2*p2=s3=new
=s2;
dynamic_cast
Student (" Joe
< Student
", " 250000000
*>( p2);");
// //s3==s2 because dynamic ob
ject checks object stored by pointer and finds student
66 Student
65
Employee**s4e1==dynamic_cast
new Employee<("Student
Joe ",*>(
1234)
e1);; // e1 is null because object s
tored by pointer is employee
-reinterpret_cast reinterprets bits of object
i.e. float* f= new float(3.25);
int* i=reinterpet_cast<int*>(f); //address of i is same as f
-reinterpret cast is dangerous, could easily lead to crashes
-can be used to emulate generics however using void*
-when compiler encounters c style cast attempts following casts
const cast, static_cast, static_cast followed by const_cast, reinterpret_cast, r
einterpret_cast followed by const_cast
-first option satisfying requirements of cast operator is selected (so m
ay employ reinterpret cast)
-c++ casts easier to find by searching
-c++ allows classes to define conversion operators specifying how objcet should
be implicitly converted to given type
i.e. in class if you want your class to to be able to made into a type done like
operator typeToConvertInto() const {
return a; // a is of TypeToConvertInto type;
} allowing
ClassName a;
typeToConvertInto s=a;
in cpp file you say
operator string() const {
ostringstream ss;
ss << _cell << " = " << _value;
return ss.str();
}
so if type of object is Cell, then can do
Cell("a1",3.14);
string s=cell;
-no return type specified because return type is specified by name of operator,
and always const because original object unchanged
-as we complete iterations, we learn development teams actual velocity and work
with it instead of estimated velocity
-thus, we may need to sort piles again for new velocity
-for planning releases, customer must prioritize stories based on; desirability
of feature to broad or important base of users, and cohesiveness of story in rel
ation to others
-customer team ultimately sets priorities in manner maximizing value delivered t
o organization
-traditional waterful model (big design up fron): write requirements, analyze th
em, design solution, code, test
-customers involed at only beginning and end
-story-driven project: customers and users involved throughout duration of proje
ct
-Good stories follow INVEST acronym: Independant, Negotiable, Valuable, Estimabl
e, Small, Testable
-independant: dependancies between stoies should be avoided because leads to pri
oritizsation and planning problems
-thus, should combine dependant stories into larger independant stories
and find different way to split story
-negotiable: stories are not contracts or reminders, but should be negotiable
-stories are only reminders to have conversation, so need to negotiate d
etails in conversation between customer team and development team (known details
are written on card however)
-i.e. shouldn't have too little detail so developers understand the requ
irement, but definitely shouldn't have too much either
-Valuable: user stories should be valuable to users and customers
-i.e. should be written so that benefits of story to customer/users are
apparent
-allows customers to prioritize stories
-Estimable: three reasons why a story might not be estimable: too big, developer
s lack domain knowledge, developers lack technical knowledge
-if developers lack domain knowledge, should discuss with customer who w
rote story
-if developers lack technical knowledge, send one or more developers on
spike: brief experiment to learn about area of application learning just enough
to estimate the task
-if story is too large, developers need to break it into smaller stories
-large stories called epics, which are useful as placeholders re
minding about big parts of system necessary to discuss
-Small: stories should be small, but not too small (i.e. A user should be able t
o add a resume)
-Testable: story that sucessfully passing its tests must proves story has been s
uccessfully developed
-untestable stories with nonfunctional requirements are bad (i.e. A user
must find software easy to use)
-User stories: emphasize conversations with users/cutomer team, comprehensible t
o customers and developers, right size, work for iterative development, encourag
e just in time developement
Lecture 9 - Design Principles
Design Principle 1: Encapsulate what varies: take part that vary and encapsulate
them, so later can alter or extend parts that vary without affecting those that
don't
-I.E. If you have a bunch of classes, i.e. TypeOfDuck, inheriting from D
uck and whether some behaviour exists in that class varies according to the subc
lass, sometimes duck fly, and sometimes ducks quack
-rather than putting methods that vary into superclass, we creat
e interface/abstract class for each behaviour that varies i.e. FlyBehaviour, Qua
ckBehaviour, and we create classes that implement those interfaces for the vario
us behaviours of the subtype, i.e. FlyWithWings, FlyUnable, Quack, Squeek, Mute