1/14 Intro
- Variables Type: Using classes to fdefin new variable types
Encapsulation:
- Interface/the API --> .h
- Implementation --> .cpp (impement methods and initialize variables)
Inclusion Guards:
- .h :
#pragma once
(included only once) - .cpp:
#inlcude "Cube.h"
- .h :
code examples::
Cube::getVolume()
means the getVolume() method of class Cube
1/16 Classes
Namespace:
- Libraries in C++, like packages in Java
- eg.
cs225::Cube; std::out
- We cannot have two classes with the same name in the same namespace.Discouraged: import everything from a namespace
- Constructor:
2.1 Default Constructor
2.2 Customized constructors
1/18 Memory
- Cube s1 // a variable containing a Cube object
Cube & s2; // a reference to a variable of type Cube
Cube * s3; // a pointer to a variable of type Cube references:
- eg.
int &j = i; // j is an alias of i
- Once the value of j changes, value of i will also be modified, and vice versa.
- eg.
pointers:
- stores a memory address
- resolve the memory address to access the data
- eg.
std::cout << "Address storing
c:" << &c << std::endl;
std::cout << "Addr. storing ptr: "<< &ptr << std::endl;
- eg.
Cube *p1; p1 = &s1
Indirection Pointers:
- &c - returns the memory address of c’s data.
- *ptr - returns the data at the memory address contained at ptr,
- ptr-> - (*ptr).getVolume() = ptr->getVolume()
Stack Memory:
- The default type memory
- Starts near the top of memory (but it does not necessarily start with the mosttop piece memory)
- Starts at a high address and it grows towards 0
- The data is read from low to high (the data is read up)
- All variables are by default on stack (automatic variables)
- Function
sizeof()
: return the size of a type in bytes. Int variable takes 4 bytes. Pointer takes 8 bytes
Stack Frame
- 申明:Each function invocation gets a stack frame.A stack frame is created whenever a function is called.
- 释放空间:A stack frame is reclaimed when a function returns, and automatically marked free (not actually freed) . When memory is marked free and it can be overwritten. (We never want to return a pointer to the stack variable)
1/23 Heap Memory
Heap Memory:
- the low memory values, grows up (opposite of Stack)
创建:Only create heap memory using keyword new :
- allocates heap memory
- calls the object’s constructor
- returns a pointer to the memory
删除:Only free heap memory using keyword delete :
- calls the object’s destructor
- marks memory as free
- Heap memory is never automatically reclaimed;If we don’t free memory on heap, we are leaking memory, We cannot access it and we cannot reclaim it;When the Heap meets the Stack, we are “out of memory”
Reference Variable:
- It never creates new memory, and it needs to be initialized when declared. It can never be redeclared. When we modify the reference variable, that would also modify the variable being aliased.
- eg.
int i = 7; int & j = i;
1/25 Function & Parameter
Arrays:
delete [] x;
Three ways to pass an argument to a function:
Pass by value:
- passed in is a copy of the original object and by changing it, we do not change the original.
- This is safe, but less efficient because it needs extra memory.
Cube joinCubes(Cube c1, Cube c2 ){}
int main() { Cube *c1 = new Cube(4); Cube *c2 = new Cube(5); Cube c3 = joinCubes( *c1, *c2 ); return 0; }
Pass by pointer:
- Passing a pointer to the original data and by changing the parameter, we are changing the original.
- This is also more efficient, but more risky. However, here we can also get an invalid parameter (NULL) passed in.
Cube joinCubes(Cube * c1, Cube * c2 )
int main() { Cube *c1 = new Cube(4); Cube *c2 = new Cube(5); Cube c3 = joinCubes( c1, c2 ); return 0; }
Pass by reference:
- Passing an alias to the variable and by changing the parameter, we are changing the original.
- This is more efficient, but risky because we are changing the original value.
Cube joinCubes(Cube & c1, Cube & c2 )
int main() { Cube *c1 = new Cube(4); Cube *c2 = new Cube(5); Cube c3 = joinCubes( *c1, *c2 ); return 0; }
Const Function Parameter:
const
is a way to prevent the parameters passed in to be changed.- We are saving the memory because we are not passing by value and at the same time to avoid the risk of changing the original.
- eg.
Cube joinCubes( const Cube & c1, const Cube & c2) {}
1/28 Lifecycle
Copy Constructors:
- Automatic copy constructor. Generated if we do not define a copy constructor. Copy every instance variable in the object
Pass by reference
Cube(const Cube & other){ ... };
Calls to constructors:
- Copy constructor is called every time when a Cube is copied by value.
shallow copy:
Tower::Tower(const Tower & other) : cube_(other.cube_), ptr_(other.ptr_), ref_(other.ref_) { //every variable copied //nothing needed in the body }
Deep copy:
Tower::Tower(const Tower & other) : ref_(other.ref_){ // Deep copy cube_: cube_ = other.cube_; // Deep copy ptr_ ptr_ = new Cube(*other.ptr_); // Deep copy ref_ (?) // Doesn’t make sense to “deep copy” an alias // Done in the Initializer List }
ptr_ = new Cube(*other.ptr_);
先dereference *other.ptr_获得一个值再放到heap上,ptr_索引上去。
Destructor:
- cleaning up heap memory and closing all the files. If we ever used new keyword, we have to free the memory (calling delete) so that we don’t leak memory.
Automatic Destructor:
- Stack memory: reclaimed when function returns
- Heap memory: reclaimed when calling delete
- Destructor is the final thing to call in the lifecycle of a class.
1/30 Inheritance
Custom destructor:
- If our member variables are on heap, we need to define a custom destructor.
Overload operators in cpp:
Cube.h
Cube operator+(const Cube & other) const; Cube & operator=(const Cube & other);
) const
-->c3 = c1.operator+(c2)
后面的const使LHSc1不变
Cube.cpp
Cube Cube::operator+(const Cube & other) const { return joinCube(*this, other); } Cube & Cube::operator=(const Cube & other) { length_ = other.length_; return
Rule of Three:
If you define any one of these three functions, you should define ALL of them.
- ■ Assignment op
- ■ Copy constructor
- ■ destructor
eg.
Cube & Cube::operator=(const Cube & other){ if (this != &other) { //If I’m not copying myself _destroy(); _copy(other); } return *this; };
Inheritance:
square.h -->
class Square : public Shape {}
- ■ Everything under Shape public is now in Square public
- ■ Do not get private variables and functions
2/1 Templates
Virtual:
- Allow us to override the function in derived classes
Evaluate rules:
- ■ Check the type of the variable
- ■ Check the matching function in that type. If virtual, go to drive type (the actual instance type)
- ■ If function not found, check the base type, repeat
- In a chain of inheritance, every class that was used as a base class need to have its functions virtual
- eg.
Virtual Destructor:
- All destructors in base classes must be virtual
- Destructors will call the base classes destructors
Templates:
Template <typename T>
- we do not need to write same function for various types
- Template type are checked at compile time
eg.
template <typename T> // 定义T的内涵 T maximum(T a, T b) { T result; result = (a > b) ? a : b; return result; }
2/4 LIST ADT
Linked Memory:
A node has two member variables:
- A list node pointer that points to the next block
ListNode * next
. - The data stored in the block
T & data
- A list node pointer that points to the next block
eg.
#ifndef LIST_H #define LIST_H template <typename T> class List { public: /* ... */ private: class ListNode { T & data; ListNode * next; ListNode(T & data) : data(data), next(NULL) { } }; }; #endif
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。