Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Linux Tipps & HardeningSecurity: Ausführen beliebiger Kommandos in perl-Dancer2 (Fedora)(29.09.2026 um 07:43 Uhr)
•
Linux Tipps & HardeningSecurity: Denial of Service in perl-HTML-FormFu (Fedora)(29.09.2026 um 07:46 Uhr)
••
Linux Tipps & HardeningSecurity: Zwei Probleme in NetworkManager-l2tp (Fedora)(29.09.2026 um 07:46 Uhr)
••
Sicherheitslücken (CVE)CVE-2026-77144 | TYPO3 Events 2 Plugin up to 10.2.11 permission(29.09.2026 um 06:21 Uhr)
•
Sicherheitslücken (CVE)CVE-2026-21753 | HCL Hive 1.0 unmaintained third party components(29.09.2026 um 06:21 Uhr)
••
Sicherheitslücken (CVE)CVE-2026-75038 | ilya-zlobintsev LACT up to 0.10.0 symlink(29.09.2026 um 06:21 Uhr)
••
Linux Tipps & HardeningSecurity: Ausführen beliebiger Kommandos in perl-Dancer2 (Fedora)(29.09.2026 um 07:43 Uhr)
•
Linux Tipps & HardeningSecurity: Denial of Service in perl-HTML-FormFu (Fedora)(29.09.2026 um 07:46 Uhr)
••
Linux Tipps & HardeningSecurity: Zwei Probleme in NetworkManager-l2tp (Fedora)(29.09.2026 um 07:46 Uhr)
••
Sicherheitslücken (CVE)CVE-2026-77144 | TYPO3 Events 2 Plugin up to 10.2.11 permission(29.09.2026 um 06:21 Uhr)
•
Sicherheitslücken (CVE)CVE-2026-21753 | HCL Hive 1.0 unmaintained third party components(29.09.2026 um 06:21 Uhr)
••
Sicherheitslücken (CVE)CVE-2026-75038 | ilya-zlobintsev LACT up to 0.10.0 symlink(29.09.2026 um 06:21 Uhr)
••
Intelligence View
⚡ tsecurity.de Intelligence

Dart Object Oriented For Beginner : Expense Manager Case Study Part 7

Lesson 7: Inheritance - Different Types of Expenses Duration: 45 minutes App Feature: 🎨 Specialized Expense Types What You'll Build: Create RecurringExpense and OneTimeExpense classes Prerequisites: Complete Lessons 1-6 What We…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!




Lesson 7: Inheritance - Different Types of Expenses



Duration: 45 minutes


App Feature: 🎨 Specialized Expense Types


What You'll Build: Create RecurringExpense and OneTimeExpense classes


Prerequisites: Complete Lessons 1-6







What We'll Learn Today



By the end of this lesson, you'll be able to:




  • ✅ Understand what inheritance means

  • ✅ Create child classes that extend parent classes

  • ✅ Use the extends keyword

  • ✅ Call parent constructors with super

  • ✅ Override methods with @override

  • ✅ Add specialized features to child classes

  • ✅ Understand the "IS-A" relationship







Part 1: The Problem - All Expenses Are the Same



Currently, all our expenses are treated identically:




void main() {
var coffee = Expense.quick('Coffee', 4.50, 'Food');
var netflix = Expense.quick('Netflix subscription', 15.99, 'Entertainment');
var birthday = Expense.quick('Birthday gift', 50.0, 'Gifts');

// But these are fundamentally different!
// Netflix repeats monthly
// Birthday gift is one-time
// Coffee is daily

// We need a way to distinguish them!
}






The Problem:




  • Some expenses repeat (subscriptions, bills)

  • Some are one-time (gifts, emergency)

  • We want to calculate yearly costs for recurring expenses

  • We want to tag one-time expenses by occasion



The Solution: Create specialized expense types using inheritance!









Part 2: Understanding Inheritance



Inheritance lets you create new classes based on existing ones.






Real-World Analogy:



Think about vehicles:




🚗 Vehicle (Parent)
├── Has wheels
├── Has engine
├── Can drive()

├── 🚙 Car (Child)
│ └── Everything from Vehicle PLUS:
│ └── Has trunk
│ └── Seats 4-5 people
│
├── 🚚 Truck (Child)
│ └── Everything from Vehicle PLUS:
│ └── Has cargo bed
│ └── Can tow()
│
└── 🏍️ Motorcycle (Child)
└── Everything from Vehicle PLUS:
└── Has 2 wheels (overrides parent)
└── Can wheelie()






Key Points:




  • Car IS-A Vehicle (IS-A relationship)

  • Car inherits all properties and methods from Vehicle

  • Car can add its own properties and methods

  • Car can override inherited methods to change behavior









Part 3: Creating Your First Child Class



Let's create RecurringExpense that inherits from Expense:




// Parent class (what we already have)
class Expense {
String description;
double amount;
String category;
DateTime date;

Expense(this.description, this.amount, this.category, this.date);

void printDetails() {
print('$description: \$${amount.toStringAsFixed(2)} [$category]');
}

bool isMajorExpense() => amount > 100;
}

// Child class - extends Expense
class RecurringExpense extends Expense {
String frequency; // New property!

// Constructor
RecurringExpense(
String description,
double amount,
String category,
this.frequency,
) : super(description, amount, category, DateTime.now());

// New method specific to RecurringExpense
double yearlyTotal() {
if (frequency == 'monthly') return amount * 12;
if (frequency == 'weekly') return amount * 52;
if (frequency == 'daily') return amount * 365;
return amount; // yearly
}
}

void main() {
var netflix = RecurringExpense('Netflix', 15.99, 'Entertainment', 'monthly');

// Can use methods from parent class
netflix.printDetails();
print('Is major? ${netflix.isMajorExpense()}');

// Can use methods from child class
print('Yearly cost: \$${netflix.yearlyTotal().toStringAsFixed(2)}');
}






Output:




Netflix: $15.99 [Entertainment]
Is major? false
Yearly cost: $191.88












Part 4: Understanding the Syntax



Let's break down the child class syntax:




class RecurringExpense extends Expense {








  • extends keyword means RecurringExpense inherits from Expense

  • RecurringExpense is the child (or subclass)

  • Expense is the parent (or superclass)




String frequency;  // New property







  • Child classes can add their own properties

  • This property doesn't exist in the parent




RecurringExpense(
String description,
double amount,
String category,
this.frequency,
) : super(description, amount, category, DateTime.now());








  • super(...) calls the parent constructor

  • Must pass required values to parent

  • Can also initialize child properties




double yearlyTotal() { ... }







  • New method that only exists in RecurringExpense

  • Parent class doesn't have this method









Part 5: Overriding Methods



Child classes can override parent methods to change their behavior:




class Expense {
String description;
double amount;
String category;
DateTime date;

Expense(this.description, this.amount, this.category, this.date);

void printDetails() {
print('$description: \$${amount.toStringAsFixed(2)} [$category]');
}
}

class RecurringExpense extends Expense {
String frequency;

RecurringExpense(
String description,
double amount,
String category,
this.frequency,
) : super(description, amount, category, DateTime.now());

// Override parent method
@override
void printDetails() {
print('🔄 RECURRING ($frequency)');
super.printDetails(); // Call parent version
print('Yearly: \$${yearlyTotal().toStringAsFixed(2)}');
}

double yearlyTotal() {
if (frequency == 'monthly') return amount * 12;
if (frequency == 'weekly') return amount * 52;
return amount;
}
}

void main() {
var regular = Expense('Coffee', 4.50, 'Food', DateTime.now());
var netflix = RecurringExpense('Netflix', 15.99, 'Entertainment', 'monthly');

print('Regular expense:');
regular.printDetails();

print('\nRecurring expense:');
netflix.printDetails();
}






Output:




Regular expense:
Coffee: $4.50 [Food]

Recurring expense:
🔄 RECURRING (monthly)
Netflix: $15.99 [Entertainment]
Yearly: $191.88









Understanding @override:






@override
void printDetails() {








  • @override annotation tells Dart you're intentionally overriding

  • Not required, but highly recommended (helps catch typos)


  • super.printDetails() calls the parent version









Part 6: Creating Multiple Child Classes



Let's create another child class for one-time expenses:




class Expense {
String description;
double amount;
String category;
DateTime date;

Expense(this.description, this.amount, this.category, this.date);

void printDetails() {
print('$description: \$${amount.toStringAsFixed(2)} [$category]');
}

String getSummary() => '$description: \$${amount.toStringAsFixed(2)}';
}

class RecurringExpense extends Expense {
String frequency;

RecurringExpense(
String description,
double amount,
String category,
this.frequency,
) : super(description, amount, category, DateTime.now());

@override
void printDetails() {
print('🔄 RECURRING ($frequency)');
super.printDetails();
print(' Yearly total: \$${yearlyTotal().toStringAsFixed(2)}');
}

double yearlyTotal() {
if (frequency == 'monthly') return amount * 12;
if (frequency == 'weekly') return amount * 52;
if (frequency == 'daily') return amount * 365;
return amount;
}
}

class OneTimeExpense extends Expense {
String occasion; // 'birthday', 'emergency', 'vacation', etc.

OneTimeExpense(
String description,
double amount,
String category,
DateTime date,
this.occasion,
) : super(description, amount, category, date);

@override
void printDetails() {
print('🎯 ONE-TIME ($occasion)');
super.printDetails();
}

bool isSpecialOccasion() {
return occasion == 'birthday' ||
occasion == 'anniversary' ||
occasion == 'holiday';
}
}

void main() {
var expenses = [
Expense('Coffee', 4.50, 'Food', DateTime.now()),
RecurringExpense('Netflix', 15.99, 'Entertainment', 'monthly'),
OneTimeExpense('Birthday gift', 75.0, 'Gifts', DateTime.now(), 'birthday'),
RecurringExpense('Gym', 45.0, 'Health', 'monthly'),
OneTimeExpense('Car repair', 350.0, 'Transport', DateTime.now(), 'emergency'),
];

print('ALL EXPENSES:\n');
for (var expense in expenses) {
expense.printDetails();
print('');
}
}






Output:




ALL EXPENSES:

Coffee: $4.50 [Food]

🔄 RECURRING (monthly)
Netflix: $15.99 [Entertainment]
Yearly total: $191.88

🎯 ONE-TIME (birthday)
Birthday gift: $75.00 [Gifts]

🔄 RECURRING (monthly)
Gym: $45.00 [Health]
Yearly total: $540.00

🎯 ONE-TIME (emergency)
Car repair: $350.00 [Transport]












Part 7: Polymorphism - Treating Different Types Uniformly



Polymorphism means "many forms" - you can treat different types the same way:




void main() {
// All three types in one list!
List<Expense> expenses = [
Expense('Coffee', 4.50, 'Food', DateTime.now()),
RecurringExpense('Spotify', 9.99, 'Entertainment', 'monthly'),
OneTimeExpense('Concert', 85.0, 'Entertainment', DateTime.now(), 'fun'),
];

// Same method call, different behavior!
for (var expense in expenses) {
expense.printDetails(); // Each type prints differently
print('');
}

// Can check type and use specific features
for (var expense in expenses) {
if (expense is RecurringExpense) {
print('${expense.description} costs \$${expense.yearlyTotal().toStringAsFixed(2)}/year');
}

if (expense is OneTimeExpense) {
print('${expense.description} is for: ${expense.occasion}');
}
}
}






Key Points:





  • List<Expense> can hold any type of Expense (parent or children)

  • Each object responds to printDetails() based on its actual type

  • Use is keyword to check the type

  • Can cast to child type to access child-specific features









Part 8: Complete Example with ExpenseManager



Let's update our ExpenseManager to work with different expense types:




class ExpenseManager {
List<Expense> _expenses = [];

void addExpense(Expense expense) {
_expenses.add(expense);
}

List<Expense> getAllExpenses() => List.from(_expenses);

// Get only recurring expenses
List<RecurringExpense> getRecurringExpenses() {
List<RecurringExpense> recurring = [];
for (var expense in _expenses) {
if (expense is RecurringExpense) {
recurring.add(expense);
}
}
return recurring;
}

// Get only one-time expenses
List<OneTimeExpense> getOneTimeExpenses() {
List<OneTimeExpense> oneTime = [];
for (var expense in _expenses) {
if (expense is OneTimeExpense) {
oneTime.add(expense);
}
}
return oneTime;
}

// Calculate yearly cost of all recurring expenses
double getYearlyRecurringCost() {
double total = 0;
for (var expense in getRecurringExpenses()) {
total += expense.yearlyTotal();
}
return total;
}

// Get count of each type
Map<String, int> getTypeCounts() {
int regular = 0;
int recurring = 0;
int oneTime = 0;

for (var expense in _expenses) {
if (expense is RecurringExpense) {
recurring++;
} else if (expense is OneTimeExpense) {
oneTime++;
} else {
regular++;
}
}

return {
'regular': regular,
'recurring': recurring,
'oneTime': oneTime,
};
}

void printSummary() {
print('\n═══════════════════════════════════');
print('💰 EXPENSE SUMMARY');
print('═══════════════════════════════════');

var counts = getTypeCounts();
print('Total expenses: ${_expenses.length}');
print(' Regular: ${counts['regular']}');
print(' Recurring: ${counts['recurring']}');
print(' One-time: ${counts['oneTime']}');

double total = 0;
for (var expense in _expenses) {
total += expense.amount;
}
print('\nTotal spent: \$${total.toStringAsFixed(2)}');

double yearlyRecurring = getYearlyRecurringCost();
print('Yearly recurring: \$${yearlyRecurring.toStringAsFixed(2)}');

print('═══════════════════════════════════\n');
}

void printAllExpenses() {
print('ALL EXPENSES:\n');
for (var expense in _expenses) {
expense.printDetails();
print('');
}
}
}

void main() {
var manager = ExpenseManager();

// Add different types of expenses
manager.addExpense(Expense('Coffee', 4.50, 'Food', DateTime.now()));
manager.addExpense(RecurringExpense('Netflix', 15.99, 'Entertainment', 'monthly'));
manager.addExpense(OneTimeExpense('Birthday gift', 75.0, 'Gifts', DateTime.now(), 'birthday'));
manager.addExpense(RecurringExpense('Gym', 45.0, 'Health', 'monthly'));
manager.addExpense(OneTimeExpense('Car repair', 350.0, 'Transport', DateTime.now(), 'emergency'));
manager.addExpense(Expense('Lunch', 12.50, 'Food', DateTime.now()));

manager.printSummary();
manager.printAllExpenses();

print('🔄 RECURRING EXPENSES BREAKDOWN:');
for (var expense in manager.getRecurringExpenses()) {
print('${expense.description}: \$${expense.amount}/${expense.frequency}');
print(' → \$${expense.yearlyTotal().toStringAsFixed(2)}/year');
}
}












🎯 Practice Exercises






Exercise 1: Create BusinessExpense Class (Easy)



Create a BusinessExpense class that extends Expense with:




  • Property: client (String)

  • Property: isReimbursable (bool)

  • Override printDetails() to show client and reimbursable status



Solution:




class BusinessExpense extends Expense {
String client;
bool isReimbursable;

BusinessExpense({
required String description,
required double amount,
required String category,
required this.client,
this.isReimbursable = true,
}) : super(description, amount, category, DateTime.now());

@override
void printDetails() {
print('💼 BUSINESS EXPENSE');
super.printDetails();
print(' Client: $client');
print(' Reimbursable: ${isReimbursable ? "Yes ✅" : "No ❌"}');
}
}

void main() {
var expense = BusinessExpense(
description: 'Client lunch',
amount: 85.0,
category: 'Meals',
client: 'Acme Corp',
isReimbursable: true,
);

expense.printDetails();
}









Exercise 2: Create TravelExpense Class (Medium)



Create a TravelExpense class with:




  • Properties: destination, tripDuration (days)

  • Method: getDailyCost() - returns amount per day

  • Method: isInternational() - returns true if destination is outside country

  • Override printDetails()



Solution:




class TravelExpense extends Expense {
String destination;
int tripDuration;

TravelExpense({
required String description,
required double amount,
required this.destination,
required this.tripDuration,
DateTime? date,
}) : super(description, amount, 'Travel', date ?? DateTime.now());

double getDailyCost() {
if (tripDuration == 0) return amount;
return amount / tripDuration;
}

bool isInternational() {
// Simple check - could be improved with a country list
return destination.contains('Japan') ||
destination.contains('USA') ||
destination.contains('Europe');
}

@override
void printDetails() {
print('✈️ TRAVEL EXPENSE');
super.printDetails();
print(' Destination: $destination');
print(' Duration: $tripDuration days');
print(' Daily cost: \$${getDailyCost().toStringAsFixed(2)}');
print(' International: ${isInternational() ? "Yes 🌍" : "No 🏠"}');
}
}

void main() {
var trip = TravelExpense(
description: 'Tokyo vacation',
amount: 2500.0,
destination: 'Tokyo, Japan',
tripDuration: 7,
);

trip.printDetails();
}









Exercise 3: Subscription Management System (Hard)



Create a SubscriptionExpense class that extends RecurringExpense with:




  • Properties: provider, plan, startDate, endDate

  • Method: isActive() - checks if subscription is currently active

  • Method: getRemainingMonths() - months until expiration

  • Method: getTotalCost() - total cost from start to end date

  • Override printDetails()



Solution:




class SubscriptionExpense extends RecurringExpense {
String provider;
String plan;
DateTime startDate;
DateTime? endDate;

SubscriptionExpense({
required String description,
required double amount,
required this.provider,
required this.plan,
required this.startDate,
this.endDate,
}) : super(description, amount, 'Subscriptions', 'monthly');

bool isActive() {
DateTime now = DateTime.now();
if (endDate == null) return true; // No end date = active
return now.isBefore(endDate!);
}

int getRemainingMonths() {
if (endDate == null) return -1; // Unlimited
DateTime now = DateTime.now();
if (now.isAfter(endDate!)) return 0;

int months = (endDate!.year - now.year) * 12 +
(endDate!.month - now.month);
return months;
}

double getTotalCost() {
if (endDate == null) {
// If no end date, calculate for 1 year
return yearlyTotal();
}

int months = (endDate!.year - startDate.year) * 12 +
(endDate!.month - startDate.month);
return amount * months;
}

@override
void printDetails() {
print('📱 SUBSCRIPTION');
print('$description ($provider - $plan)');
print('Amount: \$${amount.toStringAsFixed(2)}/month');
print('Started: ${startDate.toString().split(' ')[0]}');

if (endDate != null) {
print('Expires: ${endDate.toString().split(' ')[0]}');
print('Remaining: ${getRemainingMonths()} months');
} else {
print('Expires: Never (ongoing)');
}

print('Status: ${isActive() ? "Active ✅" : "Expired ❌"}');
print('Total cost: \$${getTotalCost().toStringAsFixed(2)}');
}
}

void main() {
var netflix = SubscriptionExpense(
description: 'Netflix Premium',
amount: 19.99,
provider: 'Netflix',
plan: 'Premium 4K',
startDate: DateTime(2024, 1, 1),
endDate: null, // Ongoing
);

var trial = SubscriptionExpense(
description: 'Adobe Creative Cloud',
amount: 54.99,
provider: 'Adobe',
plan: 'All Apps',
startDate: DateTime(2025, 9, 1),
endDate: DateTime(2025, 12, 31),
);

netflix.printDetails();
print('');
trial.printDetails();
}












Common Mistakes & How to Fix Them






Mistake 1: Forgetting to Call super()






// ❌ Wrong - parent constructor not called
class RecurringExpense extends Expense {
String frequency;

RecurringExpense(String desc, double amt, String cat, this.frequency);
}

// ✅ Correct - call parent constructor
class RecurringExpense extends Expense {
String frequency;

RecurringExpense(String desc, double amt, String cat, this.frequency)
: super(desc, amt, cat, DateTime.now());
}









Mistake 2: Wrong Parameter Order in super()






// ❌ Wrong - parameters in wrong order
RecurringExpense(String desc, double amt, String cat, this.frequency)
: super(cat, amt, desc, DateTime.now()); // Wrong order!

// ✅ Correct - match parent constructor signature
RecurringExpense(String desc, double amt, String cat, this.frequency)
: super(desc, amt, cat, DateTime.now());









Mistake 3: Not Using @override






// ❌ Wrong - typo in method name, no error!
class RecurringExpense extends Expense {
void printDetail() { // Missing 's' - creates new method instead of overriding
print('Details...');
}
}

// ✅ Correct - @override catches typos
class RecurringExpense extends Expense {
@override
void printDetails() { // Compiler checks this matches parent
print('Details...');
}
}









Mistake 4: Trying to Access Private Parent Properties






class Expense {
String _description; // Private
// ...
}

class RecurringExpense extends Expense {
@override
void printDetails() {
print(_description); // ❌ Error! Can't access private property
}
}

// ✅ Correct - use getter or make property protected
class Expense {
String description; // Public or protected
// ...
}

class RecurringExpense extends Expense {
@override
void printDetails() {
print(description); // ✅ Works!
}
}












Key Concepts Review



✅ Inheritance lets you create specialized classes based on existing ones


✅ extends keyword creates child class from parent


✅ super() calls the parent constructor


✅ @override marks methods that replace parent methods


✅ IS-A relationship - child IS-A type of parent


✅ Polymorphism - treat different types uniformly


✅ Child classes inherit all parent properties and methods


✅ Child classes can add new properties and methods


✅ Use is keyword to check object type







Self-Check Questions





1. What's the difference between inheritance and composition?



Answer:





  • Inheritance (IS-A): RecurringExpense IS-A Expense - creates specialized versions


  • Composition (HAS-A): ExpenseManager HAS-A list of Expenses - contains other objects





2. When should you use inheritance?



Answer:

Use inheritance when:




  • You have a clear IS-A relationship

  • Child needs most/all of parent's features

  • You want to treat different types uniformly (polymorphism)

  • You're specializing behavior, not completely changing it





3. What does @override do?



Answer:

@override tells the compiler you're intentionally replacing a parent method. It helps catch typos - if the method doesn't exist in parent, you'll get an error.







What's Next?



In Lesson 8: Polymorphism Deep Dive, we'll learn:




  • Working with mixed lists of different types

  • Type checking and casting

  • Abstract classes (contracts that child classes must follow)

  • Interfaces with implements

  • When to use inheritance vs interfaces



Example preview:




abstract class Payable {
void processPayment();
}

class RecurringExpense extends Expense implements Payable {
@override
void processPayment() {
// Auto-pay logic
}
}






See you in Lesson 8! 🚀









Additional Resources




  • Try creating more specialized expense types (GiftExpense, EmergencyExpense, etc.)

  • Think about what makes each type unique

  • Practice using polymorphism with mixed lists

  • Consider when inheritance makes sense vs when it doesn't



Remember: Use inheritance to model IS-A relationships and create specialized versions of existing classes. Don't force it where it doesn't fit naturally! 🌳

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Dart Object Oriented For Beginner : Expense Manager Case Study Part 7

Thematisch verwandte Begriffe: Dart, Object, Oriented, Beginner · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-102367 | mall4j through 4.0 contains an insufficient session expiration vulnerab…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag