← Back to C++ Course | Chapter 9: Inheritance | Lesson 7 of 8

C++ Hybrid Inheritance

What is Hybrid Inheritance?

Hybrid inheritance combines two or more inheritance patterns in a single class hierarchy — for example, mixing hierarchical inheritance for a set of siblings with multiple inheritance where one of those siblings also draws from a second, unrelated base class.

Example: What is Hybrid Inheritance?

cpp
#include <iostream>

class Base {
public:
	void show() { std::cout << "Base" << std::endl; }
};

class Sibling1 : public Base {};
class Sibling2 : public Base {};
class Combo : public Sibling1 {
public:
	void extra() { std::cout << "Combo" << std::endl; }
};

int main() {
	Combo c;
	c.show();
	c.extra();
	return 0;
}

The Diamond Problem Intro

The diamond problem can resurface inside hybrid hierarchies whenever a class ends up inheriting from two parents that themselves share a common grandparent, producing duplicate paths back to that shared ancestor and duplicate copies of its data.

Example: The Diamond Problem Intro

cpp
#include <iostream>

class Grandparent {
public:
	int value = 1;
};

class ParentA : public Grandparent {};
class ParentB : public Grandparent {};
class Grandchild : public ParentA, public ParentB {};

int main() {
	Grandchild g;
	// g.value would fail to compile: ambiguous, two Grandparent copies
	std::cout << g.ParentA::value << std::endl;
	return 0;
}

Resolving Ambiguity with Scope Resolution

Without virtual inheritance, you can still resolve ambiguity caused by a diamond by explicitly qualifying which inheritance path you mean using the scope resolution operator, telling the compiler exactly which parent's copy of a member you're referring to.

Example: Resolving Ambiguity with Scope Resolution

cpp
#include <iostream>

class Grandparent {
public:
	int value = 5;
};

class ParentA : public Grandparent {};
class ParentB : public Grandparent {};
class Grandchild : public ParentA, public ParentB {};

int main() {
	Grandchild g;
	std::cout << g.ParentA::value << " " << g.ParentB::value << std::endl;
	return 0;
}

Simple Hybrid Flow

When a hybrid hierarchy's inheritance paths don't actually overlap into a diamond shape, the design stays clean and predictable, letting you freely combine inheritance styles to model genuinely complex real-world relationships between types.

Example: Simple Hybrid Flow

cpp
#include <iostream>

class Engine {
public:
	void start() { std::cout << "Engine starts" << std::endl; }
};

class Wheels {
public:
	void roll() { std::cout << "Wheels roll" << std::endl; }
};

class Car : public Engine, public Wheels {};

int main() {
	Car car;
	car.start();
	car.roll();
	return 0;
}

Constructor Call Sequence

Constructor execution order in a hybrid hierarchy follows a strict, well-defined sequence, starting from the topmost base classes and working downward through every intermediate level before finally reaching the most-derived class's own constructor.

Example: Constructor Call Sequence

cpp
#include <iostream>

class Base1 {
public:
	Base1() { std::cout << "Base1" << std::endl; }
};

class Base2 {
public:
	Base2() { std::cout << "Base2" << std::endl; }
};

class Derived : public Base1, public Base2 {
public:
	Derived() { std::cout << "Derived" << std::endl; }
};

int main() {
	Derived d;
	return 0;
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.