ProgrammingC++ System/Infrastructure Developer

Tell us about the order of function and variable lookup during inheritance (name lookup, scope), as well as the ambiguities that arise with name conflicts in hierarchies (especially in virtual inheritance). How can such conflicts be resolved?

Pass interviews with Hintsage AI assistant

Answer

In C++, the order of name lookup is governed by name resolution rules that take into account scopes, hiding, and the specifics of inheritance. Key points:

  • When calling a method/accessing a variable, the search goes from the derived scope to the base scope.
  • In the case of multiple inheritance, if a name appears in both base branches, ambiguity arises.
  • Virtual inheritance helps avoid duplication (diamond problem) but also requires explicit name resolution.

Resolving conflicts:

  • For functions hidden in the derived class, you can use using:
class Base { public: void foo(int) {} }; class Derived : public Base { public: using Base::foo; void foo(double) {} // Overloaded version };
  • For variables or functions with the same names:
    • You need to explicitly specify the base class name: Base::x or Base::foo().

Example of ambiguity in diamond inheritance:

struct A { int x; }; struct B : virtual A {}; struct C : virtual A {}; struct D : B, C { void test() { x = 42; } // OK: x is unique, thanks to virtual };

Trick question

If there is a method foo(int) declared in the base class, and foo(double) in the derived class, is foo(int) accessible from an object of the derived class?

Answer: No, the method foo(double) "hides" all overloaded versions of foo from the base class. To access foo(int), you need to explicitly write using Base::foo or call Base::foo.

Example:

class Base { public: void foo(int) { } }; class Derived : public Base { public: void foo(double) {} }; Derived d; d.foo(3); // Error! foo(int) is not visible

We use:

class Derived : public Base { public: using Base::foo; void foo(double) {} }; d.foo(3); // Everything works

Examples of real errors due to ignorance of the topic nuances


Story

In a project with multiple inheritance, a class was inherited from two bases with the same foo() methods. The authors did not use virtual inheritance, leading to two copies of the base class being created — all calls to foo() became ambiguous, and the compiler refused to compile the code. This was resolved by using virtual inheritance and explicitly stating Base::foo() on the call.


Story

In a graphics engine, one derived class defined its own draw(), not using using for the base class draw(). When the code was refactored, the wrong version of draw() was called — parts of the interface stopped rendering. The error was only found after a deep examination of the class structure.


Story

When moving to a new compiler, compilation became impossible due to name ambiguities in multiple and virtual inheritance. The previously working implementation did not account for different include chains, leading to different sets of names in the translation unit.