📘 PHẦN 4: GIỚI THIỆU C++ VÀ LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
🎯 Mục tiêu tổng quát
- Hiểu sự khác biệt giữa C và C++
- Nắm vững khái niệm OOP cơ bản
- Biết cách định nghĩa và sử dụng class
- Hiểu về constructors, destructors
- Áp dụng encapsulation và data hiding
- Sử dụng operator overloading cơ bản
🧑🏫 Bài 1: Từ C sang C++ - Những khác biệt cơ bản
Hello World và namespace
cpp
// C style
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}cpp
// C++ style
#include <iostream>
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}cpp
// C++ với using namespace
#include <iostream>
using namespace std;
int main() {
cout << "Hello, World!" << endl;
return 0;
}Lưu ý: Tránh dùng using namespace std; trong header files để tránh name collision.
Input/Output với cin/cout
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
// Output
cout << "Enter your name: ";
// Input string
string name;
getline(cin, name); // Đọc cả dòng, bao gồm space
cout << "Enter your age: ";
int age;
cin >> age;
cout << "Enter your score: ";
float score;
cin >> score;
// Output với formatting
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Score: " << score << endl;
// Chain output
cout << "Summary: " << name << ", " << age << " years old, score: " << score << endl;
return 0;
}So sánh C và C++:
cpp
// C
printf("Name: %s, Age: %d\n", name, age);
scanf("%d", &age);
// C++
cout << "Name: " << name << ", Age: " << age << endl;
cin >> age; // Không cần &Biến và references
cpp
#include <iostream>
using namespace std;
int main() {
int x = 10;
// Pointer (giống C)
int *ptr = &x;
cout << "Value via pointer: " << *ptr << endl;
*ptr = 20;
cout << "x after pointer modification: " << x << endl;
// Reference (mới trong C++)
int &ref = x; // ref là alias của x
cout << "Value via reference: " << ref << endl;
ref = 30; // Không cần dereference
cout << "x after reference modification: " << x << endl;
// Reference phải được khởi tạo ngay và không thể thay đổi
// int &ref2; // ERROR!
return 0;
}Reference vs Pointer:
cpp
#include <iostream>
using namespace std;
void swapPointer(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
void swapReference(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 5, y = 10;
cout << "Before: x=" << x << ", y=" << y << endl;
swapPointer(&x, &y);
cout << "After pointer swap: x=" << x << ", y=" << y << endl;
swapReference(x, y);
cout << "After reference swap: x=" << x << ", y=" << y << endl;
return 0;
}Function overloading
C++ cho phép nhiều hàm cùng tên nhưng khác tham số.
cpp
#include <iostream>
using namespace std;
// Overload based on number of parameters
int add(int a, int b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
// Overload based on parameter types
double add(double a, double b) {
return a + b;
}
// Overload based on parameter types
string add(string a, string b) {
return a + b;
}
int main() {
cout << add(5, 10) << endl; // Calls int add(int, int)
cout << add(5, 10, 15) << endl; // Calls int add(int, int, int)
cout << add(5.5, 10.2) << endl; // Calls double add(double, double)
cout << add("Hello", "World") << endl; // Calls string add(string, string)
return 0;
}Default parameters
cpp
#include <iostream>
using namespace std;
void printInfo(string name, int age = 18, string city = "Unknown") {
cout << "Name: " << name << ", Age: " << age << ", City: " << city << endl;
}
// Default parameters với math
int power(int base, int exp = 2) {
int result = 1;
for (int i = 0; i < exp; i++) {
result *= base;
}
return result;
}
int main() {
printInfo("Alice"); // Uses defaults: 18, "Unknown"
printInfo("Bob", 25); // Uses default: "Unknown"
printInfo("Charlie", 30, "New York"); // No defaults used
cout << power(5) << endl; // 5^2 = 25
cout << power(5, 3) << endl; // 5^3 = 125
return 0;
}Lưu ý: Default parameters phải ở cuối danh sách tham số.
cpp
// ĐÚNG
void func(int a, int b = 10, int c = 20);
// SAI
void func(int a = 10, int b, int c = 20); // ERROR!Dynamic memory với new/delete
cpp
#include <iostream>
using namespace std;
int main() {
// C style
int *arr1 = (int*)malloc(5 * sizeof(int));
free(arr1);
// C++ style - single variable
int *ptr = new int;
*ptr = 42;
cout << *ptr << endl;
delete ptr;
// C++ style - array
int *arr2 = new int[5];
for (int i = 0; i < 5; i++) {
arr2[i] = i * 10;
}
for (int i = 0; i < 5; i++) {
cout << arr2[i] << " ";
}
cout << endl;
delete[] arr2; // Sử dụng delete[] cho array
// Initialize with value
int *ptr2 = new int(100); // Allocate và khởi tạo = 100
cout << *ptr2 << endl;
delete ptr2;
// Array initialization (C++11+)
int *arr3 = new int[3]{10, 20, 30};
delete[] arr3;
return 0;
}🧑🏫 Bài 2: Classes và Objects
Định nghĩa class cơ bản
cpp
#include <iostream>
#include <string>
using namespace std;
// Class definition
class Student {
public:
// Data members (attributes)
int id;
string name;
float score;
// Member function (method)
void display() {
cout << "ID: " << id << ", Name: " << name << ", Score: " << score << endl;
}
};
int main() {
// Create object
Student s1;
s1.id = 1;
s1.name = "Nguyen Van A";
s1.score = 8.5f;
s1.display();
// Create another object
Student s2;
s2.id = 2;
s2.name = "Tran Thi B";
s2.score = 9.0f;
s2.display();
// Dynamic allocation
Student *s3 = new Student;
s3->id = 3;
s3->name = "Le Van C";
s3->score = 7.5f;
s3->display();
delete s3;
return 0;
}Access specifiers
cpp
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
// Private members - chỉ truy cập được trong class
string accountNumber;
double balance;
public:
// Public members - truy cập được từ bên ngoài
string ownerName;
void setAccountNumber(string accNum) {
accountNumber = accNum;
}
string getAccountNumber() {
return accountNumber;
}
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "Deposited: " << amount << endl;
}
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "Withdrawn: " << amount << endl;
} else {
cout << "Insufficient balance!" << endl;
}
}
double getBalance() {
return balance;
}
void setBalance(double bal) {
balance = bal;
}
};
int main() {
BankAccount acc;
// OK - public member
acc.ownerName = "John Doe";
// ERROR - private member
// acc.accountNumber = "123456"; // Compile error!
// acc.balance = 1000.0; // Compile error!
// OK - through public methods
acc.setAccountNumber("123456");
acc.setBalance(1000.0);
acc.deposit(500);
acc.withdraw(200);
cout << "Owner: " << acc.ownerName << endl;
cout << "Account: " << acc.getAccountNumber() << endl;
cout << "Balance: " << acc.getBalance() << endl;
return 0;
}Ba loại access specifiers:
public: Truy cập được từ mọi nơiprivate: Chỉ truy cập được trong class (default cho class)protected: Truy cập được trong class và các class con (sẽ học ở Part 5)
Member functions
cpp
#include <iostream>
#include <string>
using namespace std;
class Rectangle {
private:
double width;
double height;
public:
// Inline member function
void setWidth(double w) {
width = w;
}
void setHeight(double h) {
height = h;
}
// Declaration only
double getArea();
double getPerimeter();
void display();
};
// Definition outside class
double Rectangle::getArea() {
return width * height;
}
double Rectangle::getPerimeter() {
return 2 * (width + height);
}
void Rectangle::display() {
cout << "Rectangle: " << width << " x " << height << endl;
cout << "Area: " << getArea() << endl;
cout << "Perimeter: " << getPerimeter() << endl;
}
int main() {
Rectangle rect;
rect.setWidth(5.0);
rect.setHeight(3.0);
rect.display();
return 0;
}Getters và Setters
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
float score;
public:
// Getters
int getId() const {
return id;
}
string getName() const {
return name;
}
float getScore() const {
return score;
}
// Setters with validation
void setId(int i) {
if (i > 0) {
id = i;
} else {
cout << "Invalid ID!" << endl;
}
}
void setName(string n) {
if (!n.empty()) {
name = n;
} else {
cout << "Invalid name!" << endl;
}
}
void setScore(float s) {
if (s >= 0 && s <= 10) {
score = s;
} else {
cout << "Invalid score! Must be 0-10" << endl;
}
}
void display() const {
cout << "Student[ID=" << id << ", Name=" << name << ", Score=" << score << "]" << endl;
}
};
int main() {
Student s;
s.setId(1);
s.setName("Nguyen Van A");
s.setScore(8.5f);
s.display();
// Validation in action
s.setId(-1); // Invalid ID!
s.setScore(15.0f); // Invalid score!
// Using getters
cout << "Student name: " << s.getName() << endl;
cout << "Student score: " << s.getScore() << endl;
return 0;
}🧑🏫 Bài 3: Constructors và Destructors
Constructor
Constructor là hàm đặc biệt được gọi tự động khi tạo object.
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
float score;
public:
// Default constructor
Student() {
id = 0;
name = "Unknown";
score = 0.0f;
cout << "Default constructor called" << endl;
}
void display() {
cout << "ID: " << id << ", Name: " << name << ", Score: " << score << endl;
}
};
int main() {
Student s1; // Constructor được gọi tự động
s1.display();
Student s2; // Constructor được gọi lại
s2.display();
return 0;
}Constructor overloading
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
float score;
public:
// Default constructor
Student() {
id = 0;
name = "Unknown";
score = 0.0f;
cout << "Default constructor" << endl;
}
// Parameterized constructor
Student(int i, string n, float s) {
id = i;
name = n;
score = s;
cout << "Parameterized constructor" << endl;
}
// Constructor with partial parameters
Student(int i, string n) {
id = i;
name = n;
score = 0.0f;
cout << "Partial constructor" << endl;
}
void display() {
cout << "ID: " << id << ", Name: " << name << ", Score: " << score << endl;
}
};
int main() {
Student s1; // Calls default constructor
Student s2(1, "Alice", 8.5f); // Calls parameterized constructor
Student s3(2, "Bob"); // Calls partial constructor
s1.display();
s2.display();
s3.display();
return 0;
}Destructor
Destructor được gọi tự động khi object bị destroy.
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
int *data; // Dynamic memory
public:
// Constructor
Student(int i, string n) {
id = i;
name = n;
data = new int[10]; // Allocate memory
cout << "Constructor called for " << name << endl;
}
// Destructor
~Student() {
delete[] data; // Free memory
cout << "Destructor called for " << name << endl;
}
void display() {
cout << "Student: " << id << " - " << name << endl;
}
};
int main() {
{
Student s1(1, "Alice");
s1.display();
} // s1 goes out of scope - destructor called
cout << "After inner block" << endl;
Student *s2 = new Student(2, "Bob");
s2->display();
delete s2; // Explicitly call destructor
cout << "End of main" << endl;
return 0;
}Copy constructor
cpp
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class String {
private:
char *data;
int length;
public:
// Constructor
String(const char *str) {
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
cout << "Constructor: " << data << endl;
}
// Copy constructor (deep copy)
String(const String &other) {
length = other.length;
data = new char[length + 1];
strcpy(data, other.data);
cout << "Copy constructor: " << data << endl;
}
// Destructor
~String() {
cout << "Destructor: " << data << endl;
delete[] data;
}
void display() {
cout << "String: " << data << " (length: " << length << ")" << endl;
}
};
int main() {
String s1("Hello");
s1.display();
String s2 = s1; // Copy constructor called
s2.display();
String s3(s1); // Copy constructor called
s3.display();
return 0;
}Shallow copy vs Deep copy:
cpp
// Without copy constructor - compiler generates shallow copy
class String {
char *data;
public:
String(const char *str) {
data = new char[strlen(str) + 1];
strcpy(data, str);
}
// No copy constructor - DANGER!
~String() { delete[] data; }
};
// Problem:
String s1("Hello");
String s2 = s1; // Shallow copy - both point to same memory
// When s1 and s2 are destroyed - DOUBLE FREE ERROR!Member initializer list
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
const int id; // const member
string name;
float &scoreRef; // reference member
static int count;
public:
// Must use initializer list for const and reference members
Student(int i, string n, float &s) : id(i), name(n), scoreRef(s) {
count++;
cout << "Constructor using initializer list" << endl;
}
// More efficient than assignment in body
// This:
// Student(int i, string n) : id(i), name(n) { }
// Is better than:
// Student(int i, string n) {
// id = i; // Assignment
// name = n; // Assignment
// }
void display() {
cout << "ID: " << id << ", Name: " << name << ", Score: " << scoreRef << endl;
}
static int getCount() {
return count;
}
};
int Student::count = 0;
int main() {
float score1 = 8.5f;
float score2 = 9.0f;
Student s1(1, "Alice", score1);
Student s2(2, "Bob", score2);
s1.display();
s2.display();
cout << "Total students: " << Student::getCount() << endl;
return 0;
}🧑🏫 Bài 4: Encapsulation và Data Hiding
Encapsulation trong thực tế
cpp
#include <iostream>
#include <string>
using namespace std;
class Employee {
private:
int id;
string name;
double salary;
string department;
// Private helper function
bool isValidSalary(double sal) {
return sal > 0 && sal <= 100000;
}
public:
Employee(int i, string n, double sal, string dept) {
id = i;
name = n;
setSalary(sal); // Use setter for validation
department = dept;
}
// Public interface
void setSalary(double sal) {
if (isValidSalary(sal)) {
salary = sal;
} else {
cout << "Invalid salary!" << endl;
}
}
double getSalary() const {
return salary;
}
void giveRaise(double percentage) {
double newSalary = salary * (1 + percentage / 100);
setSalary(newSalary);
}
void display() const {
cout << "Employee[ID=" << id << ", Name=" << name
<< ", Salary=" << salary << ", Dept=" << department << "]" << endl;
}
// Read-only access
int getId() const { return id; }
string getName() const { return name; }
string getDepartment() const { return department; }
};
int main() {
Employee emp(1, "John Doe", 50000, "IT");
emp.display();
emp.giveRaise(10); // 10% raise
emp.display();
// Direct salary access not allowed
// emp.salary = 1000000; // ERROR - private member
// Must use public interface
emp.setSalary(60000);
cout << "New salary: " << emp.getSalary() << endl;
return 0;
}Friend functions và friend classes
cpp
#include <iostream>
using namespace std;
class Box {
private:
double width;
double height;
public:
Box(double w, double h) : width(w), height(h) {}
// Friend function can access private members
friend double calculateArea(const Box &b);
friend void printBox(const Box &b);
// Friend class
friend class BoxPrinter;
};
// Friend function definition
double calculateArea(const Box &b) {
return b.width * b.height; // Can access private members
}
void printBox(const Box &b) {
cout << "Box: " << b.width << " x " << b.height << endl;
}
// Friend class
class BoxPrinter {
public:
void print(const Box &b) {
cout << "BoxPrinter: " << b.width << " x " << b.height << endl;
}
};
int main() {
Box box(5.0, 3.0);
cout << "Area: " << calculateArea(box) << endl;
printBox(box);
BoxPrinter printer;
printer.print(box);
return 0;
}Lưu ý: Friend functions phá vỡ encapsulation, nên sử dụng cẩn thận.
Static members
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
// Static data member - shared by all objects
static int totalStudents;
static double totalScore;
public:
Student(int i, string n) : id(i), name(n) {
totalStudents++;
}
~Student() {
totalStudents--;
}
void addScore(double score) {
totalScore += score;
}
// Static member function - can only access static members
static int getTotalStudents() {
return totalStudents;
}
static double getAverageScore() {
return totalStudents > 0 ? totalScore / totalStudents : 0;
}
void display() const {
cout << "Student[ID=" << id << ", Name=" << name << "]" << endl;
}
};
// Initialize static members
int Student::totalStudents = 0;
double Student::totalScore = 0;
int main() {
cout << "Initial students: " << Student::getTotalStudents() << endl;
Student s1(1, "Alice");
s1.addScore(8.5);
Student s2(2, "Bob");
s2.addScore(9.0);
cout << "Total students: " << Student::getTotalStudents() << endl;
cout << "Average score: " << Student::getAverageScore() << endl;
{
Student s3(3, "Charlie");
s3.addScore(7.5);
cout << "With s3: " << Student::getTotalStudents() << endl;
} // s3 destroyed
cout << "After s3 destroyed: " << Student::getTotalStudents() << endl;
return 0;
}Const members
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
float score;
public:
Student(int i, string n, float s) : id(i), name(n), score(s) {}
// Const member function - cannot modify member variables
int getId() const {
return id;
}
string getName() const {
return name;
}
float getScore() const {
return score;
}
void display() const {
cout << "Student[ID=" << id << ", Name=" << name << ", Score=" << score << "]" << endl;
}
// Non-const member function
void setScore(float s) {
score = s;
}
};
// Function with const reference parameter
void printStudent(const Student &s) {
s.display(); // OK - display() is const
// s.setScore(10); // ERROR - setScore() is not const
}
int main() {
Student s1(1, "Alice", 8.5f);
// Const object
const Student s2(2, "Bob", 9.0f);
cout << s2.getName() << endl; // OK - getName() is const
s2.display(); // OK - display() is const
// s2.setScore(10); // ERROR - setScore() is not const
printStudent(s1);
printStudent(s2);
return 0;
}🧑🏫 Bài 5: Operator Overloading cơ bản
Overloading arithmetic operators
cpp
#include <iostream>
using namespace std;
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// Overload + operator
Complex operator+(const Complex &other) const {
return Complex(real + other.real, imag + other.imag);
}
// Overload - operator
Complex operator-(const Complex &other) const {
return Complex(real - other.real, imag - other.imag);
}
// Overload * operator
Complex operator*(const Complex &other) const {
return Complex(
real * other.real - imag * other.imag,
real * other.imag + imag * other.real
);
}
// Overload unary - operator
Complex operator-() const {
return Complex(-real, -imag);
}
void display() const {
cout << real;
if (imag >= 0) cout << " + " << imag << "i";
else cout << " - " << -imag << "i";
cout << endl;
}
};
int main() {
Complex c1(3, 4);
Complex c2(1, 2);
cout << "c1 = "; c1.display();
cout << "c2 = "; c2.display();
Complex c3 = c1 + c2;
cout << "c1 + c2 = "; c3.display();
Complex c4 = c1 - c2;
cout << "c1 - c2 = "; c4.display();
Complex c5 = c1 * c2;
cout << "c1 * c2 = "; c5.display();
Complex c6 = -c1;
cout << "-c1 = "; c6.display();
return 0;
}Overloading comparison operators
cpp
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
float score;
public:
Student(int i, string n, float s) : id(i), name(n), score(s) {}
// Overload == operator
bool operator==(const Student &other) const {
return id == other.id;
}
// Overload != operator
bool operator!=(const Student &other) const {
return !(*this == other);
}
// Overload < operator (compare by score)
bool operator<(const Student &other) const {
return score < other.score;
}
// Overload > operator
bool operator>(const Student &other) const {
return score > other.score;
}
// Overload <= operator
bool operator<=(const Student &other) const {
return !(*this > other);
}
// Overload >= operator
bool operator>=(const Student &other) const {
return !(*this < other);
}
void display() const {
cout << "Student[ID=" << id << ", Name=" << name << ", Score=" << score << "]" << endl;
}
};
int main() {
Student s1(1, "Alice", 8.5f);
Student s2(2, "Bob", 9.0f);
Student s3(1, "Alice Clone", 7.0f);
if (s1 == s3) {
cout << "s1 and s3 have same ID" << endl;
}
if (s1 < s2) {
cout << "s1 score < s2 score" << endl;
}
if (s2 > s1) {
cout << "s2 score > s1 score" << endl;
}
return 0;
}Overloading stream operators
cpp
#include <iostream>
#include <string>
using namespace std;
class Point {
private:
int x;
int y;
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}
// Overload << operator (must be friend)
friend ostream& operator<<(ostream &out, const Point &p);
// Overload >> operator (must be friend)
friend istream& operator>>(istream &in, Point &p);
};
ostream& operator<<(ostream &out, const Point &p) {
out << "(" << p.x << ", " << p.y << ")";
return out;
}
istream& operator>>(istream &in, Point &p) {
cout << "Enter x: ";
in >> p.x;
cout << "Enter y: ";
in >> p.y;
return in;
}
int main() {
Point p1(3, 4);
cout << "p1 = " << p1 << endl; // Using overloaded <<
Point p2;
cout << "Enter coordinates for p2:" << endl;
cin >> p2; // Using overloaded >>
cout << "p2 = " << p2 << endl;
return 0;
}Overloading subscript operator
cpp
#include <iostream>
using namespace std;
class Array {
private:
int *data;
int size;
public:
Array(int s) : size(s) {
data = new int[size];
for (int i = 0; i < size; i++) {
data[i] = 0;
}
}
~Array() {
delete[] data;
}
// Overload [] operator for read
int operator[](int index) const {
if (index >= 0 && index < size) {
return data[index];
}
cout << "Index out of bounds!" << endl;
return 0;
}
// Overload [] operator for write
int& operator[](int index) {
if (index >= 0 && index < size) {
return data[index];
}
cout << "Index out of bounds!" << endl;
return data[0]; // Return reference to first element
}
int getSize() const {
return size;
}
};
int main() {
Array arr(5);
// Write using []
for (int i = 0; i < arr.getSize(); i++) {
arr[i] = i * 10;
}
// Read using []
cout << "Array elements: ";
for (int i = 0; i < arr.getSize(); i++) {
cout << arr[i] << " ";
}
cout << endl;
// Bounds checking
arr[10] = 100; // Out of bounds
return 0;
}🧪 BÀI TẬP LỚN CUỐI PHẦN: Xây dựng lớp BankAccount
Mô tả bài toán
Xây dựng hệ thống quản lý tài khoản ngân hàng với các chức năng:
- Tạo tài khoản mới
- Gửi tiền
- Rút tiền
- Chuyển tiền giữa các tài khoản
- Kiểm tra số dư
- Xem lịch sử giao dịch
- Tính lãi suất
Yêu cầu
Class BankAccount:
- Private members: accountNumber, ownerName, balance, transactionHistory
- Constructors: default, parameterized, copy constructor
- Destructor để cleanup
- Getters/Setters với validation
- Methods: deposit, withdraw, transfer, calculateInterest
- Operator overloading: <<, >>, ==, <, >
Encapsulation:
- Balance phải private, chỉ truy cập qua methods
- Validate mọi transaction (số tiền > 0, đủ số dư)
- Transaction history tự động update
Static members:
- Đếm tổng số tài khoản
- Tổng số tiền trong hệ thống
File I/O:
- Save/Load accounts từ file
- Export transaction history
Gợi ý cấu trúc:
cpp
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Transaction {
private:
string type;
double amount;
string date;
double balanceAfter;
public:
Transaction(string t, double amt, string d, double bal);
void display() const;
};
class BankAccount {
private:
string accountNumber;
string ownerName;
double balance;
vector<Transaction> history;
static int totalAccounts;
static double totalMoney;
public:
// Constructors
BankAccount();
BankAccount(string accNum, string owner, double initialBalance);
BankAccount(const BankAccount &other);
~BankAccount();
// Core operations
bool deposit(double amount);
bool withdraw(double amount);
bool transfer(BankAccount &other, double amount);
// Utilities
double getBalance() const;
void displayInfo() const;
void displayHistory() const;
double calculateInterest(double rate, int months) const;
// Static methods
static int getTotalAccounts();
static double getTotalMoney();
// Operator overloading
friend ostream& operator<<(ostream &out, const BankAccount &acc);
bool operator==(const BankAccount &other) const;
bool operator<(const BankAccount &other) const;
};
int main() {
// TODO: Implement menu-driven program
// 1. Create account
// 2. Deposit
// 3. Withdraw
// 4. Transfer
// 5. Check balance
// 6. View history
// 7. Calculate interest
// 8. Display all accounts
// 0. Exit
return 0;
}