object-oriented programming
multiple inheritance
programming concepts
software development
coding techniques

Extending from two classes

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Developers often ask how to inherit from two classes when one class has useful logic and another class has needed behavior. The answer depends on language rules and design goals, not just syntax. In many production systems, composition is safer and clearer than direct multiple inheritance.

Why Some Languages Restrict Multiple Class Inheritance

Languages such as Java and C sharp allow only one concrete base class. This avoids ambiguous behavior when two parents define methods with the same signature.

Potential ambiguity examples:

  • which parent implementation should run by default
  • how constructor chains should execute
  • how shared base-state should be initialized

Because those issues are difficult at scale, these languages prefer one class inheritance path plus interfaces.

Java and C Sharp Pattern: One Class Plus Interfaces

A practical pattern is to inherit from one base class and implement one or more interfaces.

java
1interface Auditable {
2    void audit(String message);
3}
4
5interface Retryable {
6    void retry(int attempts);
7}
8
9class BaseService {
10    protected void log(String text) {
11        System.out.println("[base] " + text);
12    }
13}
14
15public class PaymentService extends BaseService implements Auditable, Retryable {
16    @Override
17    public void audit(String message) {
18        log("audit: " + message);
19    }
20
21    @Override
22    public void retry(int attempts) {
23        log("retry attempts: " + attempts);
24    }
25}

This gives clear hierarchy with explicit behavior contracts.

Composition as the Default Design

If you need logic from two existing classes, composition often solves the problem better than inheritance.

java
1class CsvExporter {
2    String export() { return "csv-data"; }
3}
4
5class AccessChecker {
6    void ensureCanExport(String userId) {
7        if (userId == null || userId.isBlank()) {
8            throw new IllegalArgumentException("invalid user");
9        }
10    }
11}
12
13class ReportController {
14    private final CsvExporter exporter;
15    private final AccessChecker checker;
16
17    ReportController(CsvExporter exporter, AccessChecker checker) {
18        this.exporter = exporter;
19        this.checker = checker;
20    }
21
22    String exportForUser(String userId) {
23        checker.ensureCanExport(userId);
24        return exporter.export();
25    }
26}

Composition keeps dependencies explicit and test doubles easy to inject.

Python Multiple Inheritance and MRO

Python supports multiple inheritance, but method resolution order must be respected.

python
1class TimestampMixin:
2    def save(self):
3        print("timestamp")
4        super().save()
5
6class AuditMixin:
7    def save(self):
8        print("audit")
9        super().save()
10
11class RepositoryBase:
12    def save(self):
13        print("persist")
14
15class UserRepository(TimestampMixin, AuditMixin, RepositoryBase):
16    pass
17
18repo = UserRepository()
19repo.save()
20print(UserRepository.mro())

This works because each class cooperates with super and Python resolves methods in a deterministic order.

C Plus Plus and the Diamond Problem

C plus plus allows multiple class inheritance but introduces complexity such as the diamond problem, where two parents share a common ancestor. Virtual inheritance can solve duplicated base subobjects, but it adds conceptual overhead and maintenance cost.

For most business applications, prefer simpler inheritance and composition unless multiple inheritance provides a clear and necessary benefit.

When Multiple Inheritance Can Make Sense

Multiple inheritance can be useful for small, orthogonal mixins that add behavior without heavy state, especially in languages designed for that style.

Examples:

  • logging mixin
  • serialization mixin
  • validation mixin

Avoid broad parent classes with overlapping responsibilities.

Practical Design Checklist

Before inheriting from multiple sources, ask:

  1. Is this truly an is-a relationship or only code reuse?
  2. Can composition express the same behavior with lower coupling?
  3. Is method resolution obvious to future maintainers?
  4. Will testing become easier or harder?

If answers are unclear, composition is usually the safer default.

Common Pitfalls

  • Forcing inheritance to reuse code that should be delegated.
  • Combining state-heavy parent classes and creating fragile initialization order.
  • Ignoring method resolution order in Python multiple inheritance.
  • Overusing abstract base types when simple collaborators are sufficient.
  • Building deep hierarchies that hide behavior across many parent classes.

Summary

  • Multiple class inheritance rules vary by language.
  • Java and C sharp typically use one concrete parent plus interfaces.
  • Composition is often clearer and easier to test than inheritance.
  • Python supports multiple inheritance, but MRO discipline is required.
  • Prefer small, focused behavior units over complex class hierarchies.

Course illustration
Course illustration

All Rights Reserved.