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
Related
I have been trying testing if multiple definition of a friend class in different .cpp files would work. To do that I defined a main class inside main_class.hpp file:
class main_class
{
private:
int a;
int b;
int gimme_a()
{
return a;
}
public:
main_class(int a, int b) : a(a), b(b) {}
int gimme_b()
{
return b;
}
friend class main_class_friend;
};
Then I defined main_class_friend two times, firstly within main_friend_class1.cpp file:
class main_class_friend
{
main_class c;
public:
main_class_friend() : c(10, 10) {}
int gimme_a()
{
return c.gimme_a();
}
int gimme_b()
{
return c.gimme_b();
}
};
and a corresponding public test function:
void test1()
{
main_class_friend ff;
std::cout << "Gimme a: " << ff.gimme_a() << " and gimme b: " <<
ff.gimme_b() << std::endl;
}
and then I defined the second main_class_friend within main_friend_class2.cpp and a corresponding public test function:
class main_class_friend
{
private:
main_class ca;
int c;
public:
main_class_friend() : ca(9 ,9), c(11) {}
int gimme_a()
{
return ca.gimme_a();
}
int gimme_b()
{
return ca.gimme_b();
}
int gimme_c()
{
return c;
}
};
void test2()
{
main_class_friend ff;
std::cout << "Gimme a: " << ff.gimme_a() << " and gimme b: " << ff.gimme_b()
<< " and gimme c: " << ff.gimme_c() << std::endl;
}
Finally I called test1 and test2 function inside main:
int main()
{
test1();
test2();
return 0;
}
compiled the program (no errors from g++), and run it. The output was:
Gimme a: 9 and gimme b: 9
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)
What's really weird for me is that a and b were initialized by the constructor inside main_friend_class2.cpp and not the one from main_friend_class1.cpp where test1 function is defined.
Then I found that stack smashing can be easily debugged when a program is compiled with -fstack-protector flag. So I compiled it once again and the output from the program was then:
Gimme a: 9 and gimme b: 9
Gimme a: 9 and gimme b: 9 and gimme c: 11
so no more stack smashing problems, but both test1 and test2 functions use constructor from main_friend_class2.cpp file.
What's going on around here? I don't get it. Why there is a stack smashing error if there is no buffer overflow, because there isn't any buffer used?
My second question is: is there a way to define multiple times main_class_friend, but to use them in different files to make them "private" for the file inside which the class is used?
Currently I have created a class called A that creates an array of pointers to functions as well as declared the function's prototypes, please view the A.h below.
#ifndef A_H
#define A_H
class A
{
public:
//Function Definitions that will be called from the seq function below.
A::A()
//prototype functions that will be pointed to from array
void f1(int);
void f2(int);
void f3(int);
void (*funcs[3])(int);
//Destructor method
virtual ~A();
};
Then I have A.cpp defined below with the function definitions of f1, f2, f3.
A::A()
{
}
void A::f1(int a){ cout << "This is f1: " << endl; }
void A::f2(int b){ cout << "This is f2: " << endl; }
void A::f3(int c){ cout << "This is f3: " << endl; }
//Would this be valid?
funcs[0] = f1;
funcs[1] = f2;
funcs[2] = f3;
A::~A()
{
//dtor
}
How would I access the array from main.cpp
include "A.h"
.
.
.
int main()
{
//This doesn't work, what is the proper way to access the pointers to functions?
A a;
a.funcs[0](1);
}
Should print out "This is f1: ". This has really been bugging me, i've been reading different threads and even used typedefs but to no avail. Any help would truly be appreciated. If you need anymore details please let know.
I have 5 files. (1. A.hpp, A.cpp : 2. B.hpp, B.cpp : 3 main.cpp)
// A.hpp
#ifndef MY_CLASS_A
#define MY_CLASS_A
#include <iostream>
class B; // forward declaration so that I could do B * b;
struct s {
int x;
double y;
};
class A{
s my_struct;
int size;
B * b;
public:
A(int, double, int);
void f1(s);
void f2(); // this function calls B's f1 function
s get_struct();
int get_size();
void print();
};
#endif
Then I have its implementation as
// A.cpp
#include "A.hpp"
#include "B.hpp"
A::A(int x_, double y_, int size_):my_struct({x_, y_}), size(size_){}
void A::f1(s s_){
// do stuff
s_.x = 5;
s_.y = 51.99;
}
void A::f2(){
int val;
// Here I am calling B's f1 function
val = b->f1(my_struct);
}
s A::get_struct(){
return my_struct;
}
int A::get_size(){
return size;
}
void A::print(){
std::cout << " ----- " << std::endl;
std::cout << "x = " << my_struct.x << std::endl;
std::cout << "y = " << my_struct.y << std::endl;
std::cout << "size = " << size << std::endl;
std::cout << " ----- " << std::endl;
}
Then I have B
//B.hpp
#ifndef MY_CLASS_B
#define MY_CASS_B
#include "A.hpp" // I placed here A.hpp because I am
// trying to use A's struct type
class A;
class B{
public:
int f1(s); // A's struct use here to get struct by value
};
#endif
and its implementation as
// B.cpp
#include "B.hpp"
// used A's struct here again
int B::f1(s my_struct){
std::cout << "*****" << std::endl;
std::cout << my_struct.x << std::endl;
std::cout << my_struct.y << std::endl;
std::cout << "*****" << std::endl;
}
finally main as
// main.cpp
// As per comment I should place #include "A.hpp" here
#include "A.cpp"
int main(){
A a(4,9.9, 5);
a.print();
return 0;
}
My main question is how can I access the struct declared in class A into class B?
I have tried to use forward declaration by failed miserably.
Open your C++ book to the chapter on pointers and references, and read that chapter again.
"The struct declared in class A" is my_struct, which is a private class member.
To have it accessible elsewhere, you need to pass it by reference.
int B::f1(const s &my_struct){
std::cout << "*****" << std::endl;
std::cout << my_struct.x << std::endl;
std::cout << my_struct.y << std::endl;
std::cout << "*****" << std::endl;
}
Now, when you invoke this from A:
val = b->f1(my_struct);
This will now pass a reference to the my_struct member, instead of making a copy of it.
Note that the parameter is declared as a reference to a const instance of s, because f1() does not need to modify it. If it does, simply pass it as a non-const reference:
int B::f1(s &my_struct){
Now, f1() will be able to modify my_struct, and end up modifying this private instance of A's class, that was passed to it.
P.S. This has nothing to do with different translation units. Whether this whole thing is in one translation unit, or is split across half a dozen of them, classes and references work the same way.
I am trying to make a simple friend function work, but not in just one source file. I seem to get an error and I can't seem to find an answer why.
Please have a look at my code:
----------classOne.h--------------
#ifndef CLASSONE_H_
#define CLASSONE_H_
using namespace std;
class ClassOne {
private:
int m_a;
int m_b;
public:
ClassOne(int a, int b);
void printValuesOne();
friend void ClassTwo::twoPrintsOne();
};
-
----------classOne.cpp------------
#include <iostream>
#include "classOne.h"
using namespace std;
ClassOne::ClassOne(int a, int b) {
m_a = a;
m_b = b;
}
void ClassOne::printValuesOne() {
cout << "m_a: " << m_a << " " << "m_b: " << m_b << endl;
}
.
----------classTwo.h-------------
#ifndef CLASSTWO_H_
#define CLASSTWO_H_
using namespace std;
class ClassTwo {
private:
int m_c;
int m_d;
public:
ClassTwo(int c, int d);
void printValuesTwo();
twoPrintsOne();
};
#endif
-
---------classTwo.cpp-----------
#include <iostream>
#include "classTwo.h"
using namespace std;
ClassTwo::ClassTwo(int c, int d) {
m_c = c;
`enter code here`m_d = d;
}
void ClassTwo::printValuesTwo() {
cout << "m_c: " << m_c << " " << "m_d: " << m_d << endl;
}
void twoPrintsOne() {
cout << "ClassTwo: " << m_a: " << m_a << " " << "m_b: " << m_b << endl;
}
Basically ClassOne and ClassTwo are the same sort of thing, but only one of ClassTwo's method has access to all of ClassOne's members, so ClassTwo can print ClassOne's member variables. However, when I try to compile the whole program (I haven't provided the main method here), I get this error an error:
classOne.h:19:15: error: ‘ClassTwo’ has not been declared
friend void ClassTwo::twoPrintsOne();
^
Can someone help and explain?
ClassOne doesn't know about ClassTwo, therefore it cannot befriend with any of its methods. You have to add:
#include "classTwo.h"
on top of your classOne.h.
You are getting confused with what "friend" is supposed to do.
"friending" ClassTwo will allow ClassTwo to access the private members of ClassOne as if they were public.
It will not link those members between the two classes in any way.
You could have ClassTwo inherit from ClassOne, or add a ClassOne member in ClassTwo
Is there a non-macro way in C++ of printing a variable name with its value. Here is the macro way:
#define SHOW(a) std::cout << #a << ": " << (a) << std::endl
PS: I'm using Linux and do not need a cross-platform solution
No, C++ does not support reflection and the only way of doing this (as far as I know) are with macros.
You can use dynamic symbols, but then it will only work in shared libraries or executables compiled with the -rdynamic flag. And it will recognize just global variables with default dynamic visibility.
#include <dlfcn.h>
#include <iostream>
int NameMe = 42;
const char *GetName(const void *ptr)
{
Dl_info info;
if (dladdr(ptr, &info))
return info.dli_sname;
else
return NULL;
}
template<typename T>
void Dump(const T &t)
{
const char *name = GetName(&t);
if (name)
std::cout << name;
else
std::cout << "<unknown>";
std::cout << ": " << t << std::endl;
}
int main()
{
int NoName = 33;
Dump(NameMe);
Dump(NoName);
return 0;
}
$ g++ dump.cpp -ldl -rdynamic
$ ./a.out
NameMe: 42
<unknown>: 33
No way.
Without macro, you've to do this:
std::cout <<"a : " << a << std::endl;
No other way.
If you can have all your classes derive from a common ancestor, you can provide a virtual function that accomplishes this. I haven't tried this template, it might not work - some feedback would be appreciated.
struct Reflector
{
virtual void Show() = 0;
};
template<class a, char name[]>
struct ReflectorImpl : public Reflector
{
virtual void Show()
{
std::cout << name << ": " << *this << std::endl;
}
};
class MyClass: public ReflectorImpl<MyClass, "MyClass">
{
};
Yes; in C++17 you can use PFR (in C++17 mode) to get nontrivial levels of non-macro reflection. There are related mechanisms for reflecting the "string-value" of an enum.
See https://github.com/apolukhin/magic_get ;
And https://github.com/Neargye/magic_enum .