CS106L笔记:OOP
sixwalter Lv6

Object Oriented Programming

image-20230314095605396

Fundamentals

.h vs .cpp

  • .h defines public interface API
  • .cpp handle all the dirty details
image-20230314100210163

why so may extensions?

  • header file: .h, .hh, .hpp

  • source file: .cc, .cpp, .cxx, .c++, .C

  • Depends on the compiler

image-20230314100748047

Const

image-20230323093656327

Why use CONST?

There is no excuse for ignoring the safety mechanisms provided with a product, and there is particularly no excuse for programmers too lazy to write const-correct code.

same as Why don’t we use global variables?

  • “Non-const variables can be read or modified by any part of the function“ <**NOT SAFE!!!**>
image-20230314101927243
  • if we don’t use const, we can’t spot the bug easily in the above code
image-20230314102259807
  • if we use const instead of the one above:
image-20230314102420495
  • we could get errors from the compiler(compiler time error):
image-20230314102522080
  • Besides, const allows us to reason about whether a variable will be changed
image-20230314102658693

const and Classes

image-20230314103712508
  • can’t call non-const member function on const object:

Const Iterators

  • const vector::iterator itr acts like int* const itr

  • to make an iterator read-only, define a new const_iterator

image-20230314104743484 image-20230314105022855

Operators

Operator Overloading

image-20230316092301560

When dealing with user-defined class:

image-20230316092614143 image-20230316092944550
1
2
3
4
5
6
7
// member
vector<string>& vector<string>::operator+=(const string& s){
push_back(element);
return *this;
}
vec += "hello";
vec.operator+=("hello");
1
2
3
4
// const member
StringVector StringVector::operator+(const StringVector& s) const{}
// non-member
StringVector operator+(const StringVector& s1, const StringVector& s2){}

So, implement as Member of Non_Member?

  • [], (), ->, = must be implemented as member
  • <<, implemented as non-member
  • +,< if binary op treats both operands equally, implement as non-member
  • += if binary op doesn’t treat both operands equally( change lhs)
1
2
3
4
5
// non-member function
std::ostream& operator<<(std::ostream& os, const Fraction& F){
os << f.num<< "/" << f.denom;

}

POLA(Principle of Least Astonishment)

design operators primarily to mimic conventional usage

  • if operator is ambiguous , don’t overload that operator

  • use non-member functions for symmetric operators

image-20230316102026110

The second one doesn’t work if overloaded as member function.

  • always provide all out of a set of related operators
image-20230316102230667

don’t astonish others: if you implement < , you should also implement > etc.

  • always think about const vs non-const for member functions:
image-20230316104219230

image-20230316104332635

Functors (basically lambdas)

image-20230316102703125

Advanced Multi-threading Support (C++20)

1
2
3
awaiter operator co_await() const noexcept {
return awaiter{*this};
}

Special Member Functions

1
2
3
StringVector vec7 = vec4;// copy constructor
vec7 = vec2;// copy assignment
return vec7; // copy constructor

when we don’t use default copy constructor?

image-20230316112057876

when we have ownership issues:

  • ownership issues: a member is a handle on a resource outside of the class
  • pointers
  • mutexes
  • filestreams

Rule of Three

  • if you explicitly define a copy constructor, copy assignment of destructor, you should define all three

when we need to declare a destructor, we have to take care of the ownership issues, the issues happen to other two.

Move Semantics

emplace_back?

  • based on the philosophy: if you don’t need any copy, don’t do it
  • for larger objects

All things have its beginning

What happens when running the following codes?

1
2
3
4
5
6
7
8
9
10
StrVector readNames(size_t size){
StrVector names(size,"Ito");
return names;
}

int main(){
StrVector name1 = readNames(54321234);
StrVector name2;
name2 = readNames(54321234);
}
  • you may find it surprising, lots of copy constructor and destructor!
image-20230319143511666
  • so any optimization?

  • copy elision, c++17, compiler make the copy only once in the caller function(main)

image-20230319144541047

still have any further optimization ?

YES!! The cool thing move can save us more time.

in the following code:

1
name2 = readNames(54321234);
  • readNames is a temporary value, and will become homeless and will be destroyed, why we need to copy it? There is no need!
  • We could move(steal) the resources instead!

lvalue vs. rvalue

  • lvalue: has a name, can find address
  • rvalue: no name, temporary
1
2
v1[1] = 4*i; // v1[1] is a reference to named value "lvalue"
v1[2] = *ptr; // *ptr is a "lvalue" because it points to a named value

lvalue reference vs. rvalue reference

1
auto&& v4 = v1+v2; // save the rvalue, or expands its life time!
  • any changes to v4 will change (v1+v2) temporary object.
1
2
auto& ptr3 = &val; // Wrong! can't bind lvalue reference to rvalue
auto&& val2 = val; // Wrong! can't bind rvalue reference to lvalue
  • but we could bind const lvalue reference to rvalue
1
const auto& ptr3 = ptr + 5; // correct! const save us a lot!

why it works?

because you are not changing it anyway, so it is fine.

move constructor and assignment

why rvalue are key to move semantics?

  • lvalue is NOT disposable, so you can copy from, but definitely cannot move from.
  • rvalue is disposable, so you can move from
1
2
3
4
5
6
// StringVector(StringVector&& other) noexcept;
// StringVector& operator=(StringVector&& rhs) noexcept;

Axess& operator=(Axess&& rhs){
students = std::move(rhs.students); // avoid copy!
}
  • rhs itself is actually lvalue, so we need to std::move

swap

The first very primitive attempt:

1
2
3
4
5
6
template<typename T>
void swap(T& v1, T& v2){
T temp = v1;
v1 = v2;
v2 = temp;
}
  • Bad! make three copies, sadly.

with move, second attempt with the knowledge of rvalue reference:

1
2
3
4
5
6
template<typename T>
void swap(T& v1, T& v2){
T temp = std::move(v1);
v1 = std::move(v2);
v2 = std::move(temp);
}
  • Cool! We use no copy with move!

Rule of Five

  • If you declare one, you should declare all of them.(plus move constructor and move assignment)

Inheritance

Namespaces

1
2
3
4
5
6
7
8
9
10
11
12
namespace Lecture{
int count(const vector<int>& v){
int ctr = 0;
for(auto i:v){
if(i==1)
++ctr;
}
return ctr;
}

}
cout<<Lecture::count(vec)<<endl;

Motivation

interface

1
2
3
class Drink{
virtual void make() = 0;
};
  • cannot be instantiated

Abstract Classes

  • cannot be instantiated

  • has at least one pure virtual function

Non-virtual Destructors

1
2
3
4
5
6
7
8
9
10
class Base{
~Base(){}
};

class Derived: public Base{
~Derived(){}
}

Base *b = new Derived();
delete b; // Never calls the destructor for derived

Templetes vs. Derived Classes

When to use each?

static vs. dynamic polymorphism

  • Templetes: at complile time generate real codes
  • Derived Classes: at run time
image-20230323112910581

RAII

How many code paths are there ?

image-20230325110400783 image-20230325110927161

Can you guarantee there is no memory leek in the code?

image-20230325111156256
  • For normal code paths, this code is fine.
  • But if there is an exception, we will never reach the delete e.

How to enforce exception safety?

image-20230325112707980

RAII: Resource Acquisition Is Initialization

(Scope Based Memory Management) (Constructor Acquires, Destructor Releases)(Pointer to Implementation)

What is RAII?

  • all resources should be acquired in the constructor
  • all resources should be released in the destructor

an example: ifstream satisfies RAII

image-20230325113657964
  • you should not call close

another example

image-20230325114215587

fix:

image-20230325114229502 image-20230325114333457

besides:

image-20230325114736038

Is automatic memory management a good or bad thing?

image-20230325115402637

Unique Pointer

  • uniquely owns its resource and deletes it when the object is destroyed.
  • can’t be copied.
image-20230325115455131 image-20230325115919877 image-20230325120030213

Shared pointer

  • Resources can be stored by any number of shared_ptrs.
  • Delete when none of them point to it
image-20230325120328899 image-20230329101204208
  • Post title:CS106L笔记:OOP
  • Post author:sixwalter
  • Create time:2023-08-05 11:14:26
  • Post link:https://coelien.github.io/2023/08/05/course-learning/CS-106L/OOP/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.
 Comments