简体   繁体   中英

C++ class merging, linker issue

Let's consider the following situation I've discovered today by browsing through a pretty large codebase (real source exemplified for the sake of example):

One of the teams created the following two files and a set of interfaces ( MoreBase , Base ). All is fine till this point.

* file1.h *

class MoreBase
{
public:
    MoreBase();
    virtual  ~MoreBase();
};

class Base : public MoreBase
{
public:
    virtual ~Base();
    virtual void func() const = 0;
};

class A : public Base
{
public:
    A();
    ~A();
    virtual void func() const;
};

* file1.cpp *

#include <iostream>
#include "file1.h"

using namespace std;

MoreBase::MoreBase() {  cout << "file 1 MoreBase::MoreBase " << (void*)this << endl; }
MoreBase::~MoreBase() { cout << "file 1 ~MoreBase::MoreBase " << (void*)this << endl;}

Base::~Base() { cout << "file 1 ~Base::Base " << (void*)this << endl; }

A::~A() { cout << "file1 ~A::A() "<< (void*)this << endl; }

A::A() { cout << "file 1 A::A() "<< (void*)this << endl; }

void A::func() const { cout << "file 1 A::func() "<< (void*)this << endl; }

But there is another team, which is in a totally different department, building, country, continent, developing something totally different... such as the following:

* file2.h *

int some2method();

* file2.cpp *

#include <iostream>

using namespace std;

class Base
{
public:
    virtual ~Base();
    virtual void something() const = 0;
};

class B : public Base
{
public:
    B();
    ~B();
    virtual void something() const;
};

B::~B() { cout << "file 2 B::~B() "<< (void*)this << endl; }

B::B() { cout << "file 2 B::B() "<< (void*)this << endl; }

void B::something() const { cout << "file 2 B::something() "<< (void*)this << endl; }

// VARIABLE
const Base& x = B(); // ***

int some2method()
{
    x.something();
    return 42;
}

* main.cpp *

#include "file2.h"

int main()
{
    some2method();    
}

And let's compile it like:

$ g++ -ggdb main.cpp file1.cpp file2.cpp -o test

and let's run:

 $ ./test
 file 1 MoreBase::MoreBase 0x6022f0
 file 2 B::B() 0x6022f0
 file 2 B::something() 0x6022f0
 file 2 B::~B() 0x6022f0
 file 1 ~Base::Base 0x6022f0
 file 1 ~MoreBase::MoreBase 0x6022f0

Don't you consider it weird that it constructs a MoreBase object that I never requested?

Unfortunately (1) the company develops one product, so all the source files are linked into one executable.

Unfortunately (2) Base is a very common name in the domain we work...

Fortunately (1) the line marked with // *** was to be found in some2method() and the application crashed when compiled with GCC . That's where I started the investigation (right now it's outside so doesn't even crash).

And Obviously the question: How on earth is this possible? Why did the linker merge two totally unrelated classes, although they have the misfortune to share the same name. Is this undefined behaviour, defined something or simply misfortune?

EDIT : I don't request a solution to the problem (it can be fixed with namespaces, or simply renaming the not public base class), I just want to know the root cause :)

As mentioned in the comments, this breaks the one definition rule, which entails UB. The way to protect against that is to use namspaces and in particular, put any private class definition (read inside a cpp-file) inside an anonymous namespace.

EDIT: Sorry, I just realized, that WhozCraig already provided the exact same answer in the comments

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM