Object-Oriented Programming using C++ | Semester 3 Core Notes
Semester 3 - Page 5: Object-Oriented Programming using C++. 32 numbered topics, highlighted rules, worked examples, answered exam questions, three diagrams and five complete C++17 programs. General common-core guide, not an official assessed syllabus or past-paper prediction. Compare your assigned outline and compiler version.
g++ -std=c++17 -Wall -Wextra -pedantic demo.cpp -o demo, then ./demo. Inputs in main are fixed teaching examples. Book rejects negative copies. Square rejects negative/non-finite sides and sides above the square-root-of-max bound or whose computed square is non-finite. The Point demonstration requires coordinate sums to fit int; it is not an unchecked arbitrary-input arithmetic API. RAII traces show object lifetime, not a real file or device operation.Topic map
- OOP goals and objects
- C++ compilation and versions
- Classes, structs and objects
- Access and encapsulation
- Constructors and initialization
- explicit and conversions
- Copy constructors and assignment
- Destructors and lifetime
- RAII and ownership
- Rule of zero, three and five
- Move semantics
- References, pointers and const
- this and member functions
- Static members and friends
- Composition and aggregation
- Public inheritance
- Multiple and virtual inheritance
- Overloading and name hiding
- Virtual functions and override
- Abstract classes and interfaces
- Virtual destructors and slicing
- Construction-time dispatch
- Operator overloading
- Templates and generic code
- Containers and iterators
- Exceptions and guarantees
- Smart pointers
- Streams and validation
- Files and resource scope
- Namespaces and separate definitions
- Design and test boundaries
- Revision and portability limits
1. OOP goals and objects
Object-oriented design groups state and behavior behind contracts. Encapsulation, abstraction, inheritance and polymorphism are related but distinct.
Answer: No. Choose a design for its contracts and complexity, not a feature checklist.
2. C++ compilation and versions
Compile translation units, then link definitions. Standard mode and library support matter. These examples target C++17 and use standard headers, not bits/stdc++.h.
Answer: No. Use the selected language version and verify required library support.
3. Classes, structs and objects
A class describes a type; each object has a lifetime and state. class defaults to private members/inheritance, struct to public; both can have methods.
Answer: No. It supports the same class mechanisms with different defaults.
4. Access and encapsulation
private limits access to class members/friends; protected also serves derived-class contexts; public is the client interface. Preserve invariants at every public boundary.
Answer: No. Constructors and methods must enforce the invariant.
5. Constructors and initialization
Constructors establish valid objects. Member initializers initialize directly; members are initialized in declaration order, not the written initializer-list order.
Answer: No. It initializes the object rather than returning an ordinary function result.
Validated Book value and copying
#include <iostream>
#include <stdexcept>
class Book {
int copies_;
public:
explicit Book(int copies) : copies_(copies) {
if (copies < 0) throw std::invalid_argument("negative copies");
}
bool borrow() {
if (copies_ == 0) return false;
--copies_; return true;
}
int available() const { return copies_; }
};
int main() {
Book original(2), copy = original;
std::cout << std::boolalpha;
std::cout << copy.borrow() << ' ' << copy.borrow() << ' '
<< copy.borrow() << '\n';
std::cout << "original: " << original.available()
<< "; copy: " << copy.available() << '\n';
try { Book invalid(-1); }
catch (const std::invalid_argument&) { std::cout << "negative rejected\n"; }
}Checked output:
true true false original: 2; copy: 0 negative rejected
6. explicit and conversions
explicit stops unintended implicit constructor conversion and selected conversion-function uses. Direct initialization can still call an explicit constructor.
Answer: No. It narrows conversion contexts.
7. Copy constructors and assignment
Copy construction creates a new object from another; copy assignment changes an existing object. Standard value members usually supply correct default copying.
Answer: No. A raw pointer member normally copies its address, not the pointed-to object.
8. Destructors and lifetime
Destruction ends an object's lifetime and destroys owned members in reverse order. Automatic objects are destroyed at scope exit, including normal exception unwinding.
Answer: No. It can cause later automatic destruction of an already-ended object.
9. RAII and ownership
Tie resource lifetime to an owning object's lifetime. Prefer standard containers and smart pointers to raw owning new/delete. Raw pointer syntax alone does not state ownership.
Answer: No. Locks, file handles and other resources can have owners too.
RAII cleanup on exception path
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
struct Tracer {
std::string name;
explicit Tracer(std::string label) : name(std::move(label)) {
std::cout << "acquire " << name << '\n';
}
~Tracer() { std::cout << "release " << name << '\n'; }
};
int main() {
try {
auto first = std::make_unique<Tracer>("first");
auto second = std::make_unique<Tracer>("second");
throw std::runtime_error("demo failure");
} catch (const std::runtime_error&) {
std::cout << "handled\n";
}
}Checked output:
acquire first acquire second release second release first handled
10. Rule of zero, three and five
Prefer rule of zero with value/RAII members. A raw-owning-resource type needs deliberate copy/destruction behavior; C++11 move operations extend the usual rule-of-three discussion to five.
Answer: No. Unnecessary custom members can inhibit useful implicit operations.
11. Move semantics
Move operations may transfer resources from expiring objects. std::move is a cast enabling overload selection, not a transfer by itself. Moved-from guarantees depend on the type.
Answer: No. Many standard-library objects are valid but have unspecified state; follow their documented guarantees.
Single-owner move and value composition
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <utility>
struct Library { std::vector<std::string> titles; };
int main() {
auto owner = std::make_unique<Library>();
owner->titles = {"C++", "Algorithms"};
auto destination = std::move(owner);
std::cout << std::boolalpha << "source empty: " << !owner << '\n';
std::cout << "destination titles: " << destination->titles.size() << '\n';
Library copy = *destination;
copy.titles.push_back("Math");
std::cout << "original: " << destination->titles.size()
<< "; value copy: " << copy.titles.size() << '\n';
}Checked output:
source empty: true destination titles: 2 original: 2; value copy: 3
12. References, pointers and const
References alias objects; pointers may be null. const member functions cannot normally mutate non-mutable data through this. A const reference avoids a copy but does not extend every source lifetime.
Answer: No. External mutation, mutable members and shared resources still need synchronization.
13. this and member functions
this points to the current object in a non-static member function. Returning *this by reference supports chaining while preserving identity.
Answer: No. It has no implicit object.
14. Static members and friends
Static data belong to the class rather than each instance. Friends get specified private access; friendship is not automatically inherited, symmetric or transitive.
Answer: Not merely because they are declared as friends.
15. Composition and aggregation
Composition models an owned has-a relationship; aggregation is a looser lifetime relationship. State whether a member owns or merely observes another object.
Answer: No. Has-a and substitutable is-a express different contracts.
16. Public inheritance
Public inheritance should preserve base-type promises. Derived objects include base subobjects; access mode controls accessibility of inherited members, not whether base storage exists.
Answer: No. They remain in its base subobject but are not directly accessible to derived code.
17. Multiple and virtual inheritance
Multiple inheritance adds several bases. A repeated common base may create ambiguity. Virtual inheritance shares one virtual base subobject; the most-derived constructor initializes it.
Answer: No. Shared base layout and function dispatch are separate features.
18. Overloading and name hiding
Overloading selects among same-name functions with different parameter lists. Derived declarations can hide base overloads; using Base::name can reintroduce them.
Answer: No. Only the appropriate virtual signature overrides.
19. Virtual functions and override
A virtual call through a base pointer/reference can dispatch to the final overrider. override detects signature mistakes; final restricts further overriding/inheritance as applicable.
Answer: No. cv/ref qualifiers matter for overriding.
Validated virtual dispatch and ownership
#include <iostream>
#include <memory>
#include <cmath>
#include <stdexcept>
#include <limits>
struct Shape {
virtual double area() const = 0;
virtual ~Shape() = default;
};
class Square final : public Shape {
double side_;
public:
explicit Square(double side) : side_(side) {
if (!std::isfinite(side) || side < 0 ||
side > std::sqrt(std::numeric_limits<double>::max()) ||
!std::isfinite(side * side))
throw std::invalid_argument("invalid side");
}
double area() const override { return side_ * side_; }
};
int main() {
std::unique_ptr<Shape> shape = std::make_unique<Square>(3);
std::cout << "area: " << shape->area() << '\n';
Shape& reference = *shape;
std::cout << "reference: " << reference.area() << '\n';
try { Square invalid(-1); }
catch (const std::invalid_argument&) { std::cout << "negative rejected\n"; }
}Checked output:
area: 9 reference: 9 negative rejected
20. Abstract classes and interfaces
A pure virtual function makes a class abstract until the required final overriders are supplied. Pure virtual destructors still need a definition if used.
Answer: No. Pointers and references to it are permitted.
21. Virtual destructors and slicing
Delete through a polymorphic base pointer only with the correct destruction contract, normally a public virtual destructor. Copying a derived value into a base value slices its derived portion.
Answer: Not generally. Value copying can slice; use a deliberate ownership/reference design.
22. Construction-time dispatch
During base construction/destruction, virtual dispatch does not reach a more-derived part whose lifetime is not active. Avoid calling pure virtual functions on that path.
Answer: No. Lifetime-stage rules still apply.
23. Operator overloading
Operators can express natural value operations but cannot invent new precedence or overload every operator. Keep algebraic expectations clear and avoid surprising side effects.
Answer: No. Parsing rules remain fixed.
Point operator and template value selection
#include <iostream>
#include <string>
struct Point { int x, y; };
/* Demo contract: coordinate sums fit int. */
Point operator+(Point a, Point b) { return {a.x + b.x, a.y + b.y}; }
template<class T>
T maximum(T a, T b) { return a < b ? b : a; }
int main() {
Point p = Point{2, 3} + Point{4, -1};
std::cout << "point: " << p.x << ',' << p.y << '\n';
std::cout << "max int: " << maximum(4, 7) << '\n';
std::cout << "max text: " << maximum(std::string("cat"), std::string("car")) << '\n';
}Checked output:
point: 6,2 max int: 7 max text: cat
24. Templates and generic code
Templates parameterize types/values; operations in the implementation constrain supported types. Instantiation errors can expose an unmet requirement.
Answer: No. The body must be valid for the chosen arguments.
25. Containers and iterators
vector owns contiguous elements; string owns text. Iterators denote positions and have container-specific invalidation rules. Avoid retaining a vector pointer across reallocation.
Answer: No. Exceeding capacity or other operations can invalidate them.
26. Exceptions and guarantees
Throw reports failure to a handler; catch by const reference for typical standard exceptions. RAII releases owners during stack unwinding. Basic, strong and no-throw guarantees differ.
Answer: No. Preserve state invariants and handle only where a useful recovery exists.
27. Smart pointers
unique_ptr is single ownership and non-copyable. shared_ptr shares ownership; weak_ptr observes without adding strong ownership. Avoid strong reference cycles.
Answer: No. Ownership-count safety is not shared-object synchronization.
28. Streams and validation
Formatted extraction sets stream state on failure. Check extraction and validate ranges separately. For strict whole-line numeric input, reject trailing junk deliberately.
Answer: No. Inspect stream state and validation results.
29. Files and resource scope
Use RAII file streams and check opening, read/write and close/flush status appropriate to the task. Do not overwrite personal files for examples.
Answer: No. Durability guarantees depend on the platform and storage protocol.
30. Namespaces and separate definitions
Namespaces organize names; declarations and definitions have different roles. One-definition-rule constraints govern how entities appear across translation units.
Answer: No. It can pollute clients' lookup and create collisions.
31. Design and test boundaries
Prefer small contracts, composition and clear ownership. Test normal, boundary, invalid and polymorphic behavior; compile warnings help but are not a proof.
Answer: No. Use tests and reasoning matched to the contract.
32. Revision and portability limits
State the C++ version, ownership, lifetime and preconditions before explaining a trace. These are common-core notes, not a college-syllabus certification.
Answer: Complete source, build command, checked output, validation policy and limitations.
Concept comparison
| Concept | Meaning | Common mistake |
|---|---|---|
| Overload | Same name, different parameters | Return type alone does not distinguish ordinary overloads |
| Override | Derived implementation of virtual signature | Missing const/ref qualifier changes signature |
| Composition | Own/use another object | Has-a is not inheritance |
| Public inheritance | Substitutable base contract | Code reuse alone is insufficient |
| RAII | Ownership follows object lifetime | Raw pointers do not state ownership |
| unique_ptr | Single owner | Cannot copy ownership |
| shared_ptr | Shared ownership | Does not synchronize object data |
| const | Restricted modification through this access | Does not guarantee thread safety |
Checked trace reference
| Example | Result | Contract |
|---|---|---|
| Book copy borrows three times | true,true,false; original2,copy0 | Initial2, value copying |
| Square through Shape | 9 | Finite side3, virtual method/destructor |
| RAII exception cleanup | second then first, then handled | Completed local owners unwind |
| Point2,3 plus4,-1 | 6,2 | Sums fit int |
| maximum4,7 | 7 | Comparable int values |
| unique_ptr move | sourceempty, destination2titles | Unique ownership guarantee |
| Value Library copy | original2,copy3titles | vector/string value members |
Revision checklist
- Explain valid state and access boundaries.
- Trace initialization, copy/move and destruction.
- State ownership and lifetime of every pointer/reference.
- Separate overload, override, hiding and slicing.
- Use composition or substitutable inheritance deliberately.
- Test invalid inputs and exception cleanup as well as happy paths.
- Check version, iterator validity and numeric preconditions.
Practice resources
Continue with the C++ OOP Lab File, Lab Files index and Online Compiler: choose C++.
Sources
Language/reference pages support the rules; explanations, diagrams and complete programs here are original teaching material. Later-version features shown by a reference are not required by these C++17 examples.
Comments
Post a Comment