Problem List
-
Class 8: The implementation of an ADT might not be different than the implementation of another. A LinkedList can be used to implement Lists, Sets, Collections (*), Queues, Stacks, Deques, etc. Is this a good approach? What about class invariants?
Yes—a linked-list can power many ADTs (lists, sets, collections, queues, stacks, deques, etc.).
But class invariants complicate things: some ADTs (e.g., a set) must inspect the whole list to ensure no duplicates, whereas queues, stacks, and deques need no extra checks.Reusing the list saves effort by simply exposing the right interfaces, yet it also crams every method from all those ADTs into one class, mixing unrelated responsibilities and lowering cohesion. So reuse brings both clear benefits and clear drawbacks.
-
Comparable
, and Comparable<? super T> Comparable
: must compare to its own type T only.
Comparable<? super T>: may compare to T or any of T’s supertypes—more flexible. -
Comparator
Comparable: object defines its own natural order via compareTo ( this vs. other ).
Comparator: separate object that defines arbitrary orderings via compare(a, b), letting you sort the same type in multiple different ways(customize). -
List<Long> l = new LinkedList<Long>();
orLinkedList<Long> l = new LinkedList<Long>();
List
l = new LinkedList ();
• Variable typed to the interface List.
• You can later swap in any other List implementation (e.g., ArrayList) without changing the rest of the code.
• Only List-level methods are available at compile time.LinkedList
l = new LinkedList ();
• Variable typed to the concrete class.
• Tied to LinkedList; harder to replace with another List type.
• Gives access to LinkedList-specific methods (like addFirst, removeLast) in addition to the List interface. -
What the use of
.parallel()
in stream?.parallel() turns the stream into a parallel stream: the elements are processed by multiple thread
-
Class 9
Implementing a sort method
Let’s use selection sort to keep it simple
What if we want a different ordering of our elements (like, sort in reverse order), what can we do?
Change comparator to negative
-
Task 6 Can you have proper generic classes and methods in Python, justify?
Yes, Python supports proper generic classes and Yes—Python supports generics (
TypeVar
) for static type-checking. The type parameters are only metadata; the interpreter doesn’t enforce them at runtime -
Explain
Memory is a sequence of bytes. Every address has a value.
-
struct
Behaves like class except all fields are public.
-
const
everywhereCannot change the value pointed toconst T * data;
var
.Value is a constant but the pointer is not
Cannot change the pointer address.T * const data;
Pointer is constant but the value is not.
Fix everything.const T * const data;
const
after function name: function body does not change any state. -
NULL
andnullptr
in C++
NULL
is a macro expands to0
(or((void *)0)
).
nullptr
is a type that unambiguously represents “no pointer” in C++. -
Why you should NOT return pointers to a function's local variables.
- Local variables will be destoryed when leaving the function
- Memory previously occupied by local variables is now considered "garbage" or available for reuse.
- There is no guarantee that the value will still be the one that you want.
#include <stdlib.h> #include <stdio.h> int * foo(int baseValue) { int myLocalVariable = baseValue; if (myLocalVariable % 2 != 0) { myLocalVariable++; } else { myLocalVariable = myLocalVariable * 2; } return &myLocalVariable; // DANGER: Returning address of local variable } int bar(int baseValue) { int myLocalVariable = baseValue; if (myLocalVariable % 2 != 0) { myLocalVariable--; } else { myLocalVariable = myLocalVariable / 2; } return myLocalVariable; // SAFE: Returning value } int main(void) { int * ptrToValue = foo(32); // ptrToValue gets address of foo's myLocalVariable (which was 64) // foo's stack frame is now GONE. ptrToValue is dangling. printf("Printing foo's local variable: %d\n", *ptrToValue); // UNDEFINED BEHAVIOR printf("Printing bar's return value: %d\n", bar(32)); // bar(32) returns 16. Safe. // The call to bar and printf likely overwrote // the memory ptrToValue points to. printf("Re-printing foo's local variable: %d\n", *ptrToValue); // UNDEFINED BEHAVIOR, very likely garbage or crash }
-
Two ways to use a method of a.cpp in main.cpp
-
a.hpp
#ifndef A_H #define A_H void foo(); #endif
a.cpp
#include "a.h" void foo() { //..... }
main.cpp
2. #include "a.h" int main() { foo(); return 0; }
a.cpp
void foo() { //..... }
main.cpp
extern void foo(); int main() { foo(); return 0; }
-
-
Templates in C++
Compiler will specialize different functions for different type usages.
Advantages: code generated during compilation.
Disadvantage: duck-typing(A template accepts any type. During instantiation the compiler simply checks “does the type support every operation I happen to use inside the template?” If the answer is yes, the code compiles; if not, the instantiation fails.)
Specifying restrictions using concepts (template types itself does not add any constraints).
Since C++20.typedef Stack<float> FloatStack; FloatStack fs = FloatStack(5);
Adds constraints to templates.
which requiresconcept Comparable = requires(T a, T b) { { a.compares_to(b) } -> std::same_as<int>; }
T
to have a member functionint compare_to(T other)
. -
Destructor
Value data members are destructed automatically when the parent object gets destructed.
## Static vs non-static Java
Static does not require an instance or a object, while non-static does.
-
Singleton
• Design pattern that guarantees exactly one instance of a class and provides global access to that instance.
### Nested class
• A class declared inside another class (“enclosing class”).
• Purpose: grouping—indicates the inner class is used only by its outer class, can access itsprivate
members if declaredfriend
or isprivate
itself.
• Visibility modifiers (public
,protected
,private
) on the nested definition control how clients see it; it does not automatically get access to outer members unless such access is granted. -
#### 1. Why an array of pointers to Figure?
Because we need to store different child types (like
Circle
andRectangle
) in one list. This lets C++ use polymorphism—calling the rightdraw()
for each shape.#### 2. We cannot define a variable of class Figure, why?
Figure
is an abstract class because it has a pure virtual function (likevirtual void draw() = 0;
). This meansFigure
can not be instantied -
#### 1. Can we have multiple implementations of these types and functions at the same time?
- Simple answer: Yes! This is the point of data abstraction. You can have different "versions" (implementations) of the list—like one using arrays (fast for random access) and another using linked nodes (good for inserting/deleting). Each version defines the same functions (e.g.,
add
,size
) but works differently inside. In C++, you could use classes or templates to switch between them without changing your main code. It's like having two car engines that fit the same car—you pick one based on what you need (speed vs. fuel efficiency).
#### 2. Can we use multiple implementations of these types and functions at the same time?
- Simple answer: Absolutely, and it's useful! In the same program, you could create one list using an array implementation (e.g.,
ArrayList myList1;
) and another using a linked list (e.g.,LinkedList myList2;
). Both would have the same functions (likesize()
oradd()
), so your code treats them the same way.
#### 3. Why choose the name list.size?
- Simple answer: We choose
size
because it's clear and describes exactly what it does—returns how many items are in the list (e.g., 0 for empty, 5 for a list with 5 things). It's like naming a button "Play" on a music app instead of "DoThing42"—easy to understand and remember. In C++, this could be a member function likeint List::size() const { return itemCount; }
. The slide mentions for a NULL (empty) list,size
returns 0, which makes sense—no items means size zero!
#### 4. Why choose the name list.drop?
- Simple answer:
drop
is a simple name that means "get rid of" or "delete" the list and free up its memory. It's like dropping trash in a bin—you're cleaning up. In C++, this could be like a destructor (~List()
) or a function to clear everything (e.g.,void List::drop() { /* free memory */ }
). We pick short, meaningful names so code is easy to read, not confusing like "destroyListNow".
#### 5. Can we have a "List of T" where T is a specific type?
- Simple answer: Yes, definitely! This is where C++ shines with templates. You can make a generic
List<T>
whereT
is a placeholder for any type—likeList<int>
for a list of numbers, orList<string>
for a list of words. It's like a reusable box that can hold apples (int) or oranges (string)—you specify the type when you create it. In code:template <typename T> class List { /* functions like add(T item) */ };
. The slide's example seems like a basic int list, but templates make it flexible for any "T".
- Simple answer: Yes! This is the point of data abstraction. You can have different "versions" (implementations) of the list—like one using arrays (fast for random access) and another using linked nodes (good for inserting/deleting). Each version defines the same functions (e.g.,
-
Data abstraction is one of the most essential and important features of object-oriented programming in C++. Abstraction means displaying only essential information and ignoring the details. Data abstraction refers to providing only essential information about the data to the outside world, ignoring unnecessary details or implementation.
Data abstraction - This type only shows the required information about the data and ignores unnecessary details.
-
Every expression has a type. For type checking, etc.(The compiler knows the type of every expression before the program runs.)
-
Python does not have genericity because No strict mechanism for constraining types.
-
Difference between function and method
### Function
Object independent. Can only have side effects on global variabls.
### Methodint add(int a, int b) // pure function example { return a + b; // no hidden state touched }
Object dependent. Can affect object internals.
class Counter { int value_{0}; // object’s private data public: void increment() { ++value_; } // method mutates *this* int value() const { return value_; } };
-
Modularization
Java: class. C++: header. Python: module
-
Java
OOP
Genericity can only be used with classes(object types).
Generic arrays can only be created from specific types, no generic array creation is allowed.
Functions cannot be passed as arguments directly in Java, they are objects underneath.class Box<T> { // T[] a = new T[10]; error }
Universal bytecode, specific JVM.
JIT compiler is provided (bytecode to native code on runtime if they are being run frequently).
Static type checking (compilation time)
Runtime type checking when for example casting and
instanceof
Interpreted (compile first)
## Python
Everything is an object (local variable, function, class, field, method, etc.)
Flexible.
Dynamic type checking during runtime.
No way to define type restrictions.
Interpreting, without preprocessing.
Duck typing.
Define before use.
## C++
Multiparadigm.
Support procedual, object-oriented, functional, etc.
Overload override (function/operator)
Naming collision issue (same name between variables and functions)
Static type checkng
Generics are supported by templates, but copying class/structure/etc.
Templates do not offer restrictions.
Solutions:
Leave it to compilers
Parameterized abstraction (require generic function for every operation)
Concepts
-