CS247 Lecture 1
Abstract Data Type Allow us to hide complex details behind an interface. A client only needs to understand the interface to use a class, they are free to ignore the underlying implementation.
Examples:
- BST - client will call insert/delete/search - don’t need to worry about tree balancing.
- Dictionary - can simply insert/lookup values - no worries about internals,hash function being used, etc.
Ideally, use the compiler to enforce certain properties of the ADT. Example: Linked List ADT: One property we may wish to have is that all nodes are on the heap
Detecting issues at compiler-time ensure that users of our software never encounter this particular suite of run-time bugs. We wish to prevent tampering and forgery of our ADTs.
Forgery:
- creating invalid instances of an ADT. Tampering:
- Modifying a valid instance of an ADT to become invalid in an unexpected way.
Example: Rational ADT
What is Prevents implicit conversions. the explicit keywork?
- Used for single parameter constructors
- Prevents implicit conversions For example:
Without the explicit keyword, this will compile f(247). However without the explicit keyword, this won’t work. You will need to write:
Another example:
- Using explicit can be helpful to catch mistakes:
Another example: This works because std::String has a single-parameter ctor which takes in a char* and is non-explicit:
Does the Rational ADT need to be a class?
- Not necessarily
- ADTs are abstract - not tied to one particular implementation
- Could use a struct
- Classes are nicer:
- Construction/destruction is guaranteed (on the stack)
- Can enforce legal value ranges via access specifiers (public/private/protected)
- With a c struct: someone can easily set denom = 0. Not possible with our class: denom is private, we could add logic to our ctor to reject denom = 0.
This is an example of an Invariant: We gave Rational a default ctor - ctor that can be called with no arguments. Should all ADTs have a default ctor? Not necessarily - only if it makes sense.
Consider a Student ADT with name, id, birthday fields - no sensible defaults.
If you do not write any ctors at all, you get a compiler provided default ctor: (can be called with no arguments)
- Leaves primitive fields unitialized (garbage vales)
- Default constructs object fields. If you write any ctor yourself, the compiler provided ctor is not supplied.
Do we need 3 ctors?
- No - we can use default parameters to better code styles
Default parameters must be trailing Consider:
If we were to call Foo{5} - which stor are we trying to call here? z = 5, or x = 0 and y = 5?
Ambiguous - won’t compile - default parameters must be trailing. Additionally - default parrameters only appear in the declaration, not the definition.
We;ve use the MIL - member initialization list to set our fields: What’s the difference between:
In general, using the MIL is considered better. To understand why - think about object construction. Happens in 4 steps:
- Space is allocated (stack or heap)
- Call the superclass ctor
- Initizalize fiels via MIL
- Run the ctor body
Next: CS247 Lecture 2