I have an interesting problem that crept up and I was wondering why GCC/G++ doesn't catch this and throw some kind of error.
Apologies for how many files this takes, but I've reduced the problem as much as possible.
Interface.H
class BaseClass {
public:
virtual void hello() = 0;
};
void rememberClass(BaseClass* foo);
void callFunc();
Interface.C
#include "Interface.H"
namespace {
typedef void (BaseClass::*memfunptr)();
memfunptr func;
BaseClass* obj;
}
void rememberClass(BaseClass* foo) {
func = &BaseClass::hello;
obj = foo;
}
void callFunc() {
(obj->*func)();
}
Class1.H
class Class1 {
public:
Class1();
};
Class2.H
class Class2 {
public:
Class2();
};
Class1.C
#include "Interface.H"
#include "Class1.H"
#include <iostream>
class HelloClass : public BaseClass {
public:
HelloClass() {}
void hello() {
std::cout << "Calling Hello" << std::endl;
}
};
Class1::Class1() {
HelloClass* foo = new HelloClass();
rememberClass(foo);
}
Class2.C
#include "Interface.H"
#include "Class2.H"
#include <iostream>
class HelloClass : public BaseClass {
public:
HelloClass() {}
void hello() {
std::cout << "Calling Hello 2" << std::endl;
}
};
Class2::Class2() {
HelloClass* foo = new HelloClass();
rememberClass(foo);
}
main.C
#include "Class2.H"
#include "Interface.H"
int main(int argc, char** argv) {
Class2 a;
callFunc();
}
Output
g++ Class1.C Interface.C main.C Class2.C
./a.out
Calling Hello
As you can see above, Even though I am constructing a Class2, it prints the output from Class1. This is because the vtable for HelloClass in both the Class1 and Class2 have the same address for HelloClass::hello(), and it is the address of the function in Class1.C
I'm assuming that this is because when GCC is doing the linking, it sees vtables for classes with the same mangled names and just discards one of them. But should it warn about this? Or even cause an error. I have tried with -Wall and -Wextra but nothing is mentioned.
No, the standard explicitly allows the compiler to silently do the wrong thing in this case.
Explicitly, you are causing Undefined Behavior by having two conflicting definitions for the same decorated name in the same program.
It is called the ODR "One Definiton Rule".
Chapter 3.2.
Use explicit name for namespaces
Related
I am unable to call private methods of derived class using pointer to base class returned by Factory method.
I would like to return a unique_ptr to Cat when user is running on WIN and unique_ptr to Dog when user is running on Linux.
Base.h pure virtual class
#include <iostream>
#include <memory>
class Base
{
public:
virtual void echo() = 0;
};
Cat.h - derived class of Base
#include "Base.h"
class Cat : public Base
{
public:
void echo();
void CatPrivateFunction();
};
Cat.cpp
#include "Cat.h"
void Cat::echo()
{
std::cout << "In echo()" << std::endl;
}
void Cat::CatPrivateFunction()
{
std::cout << "In CatPrivateFunction()" << std::endl;
}
Dog.h - derived class of Base
#include "Base.h"
class Dog
{
void echo();
void DogPrivateFunction();
};
Dog.cpp
#include "Dog.h"
void Dog::echo()
{
std::cout << "In echo()" << std::endl;
}
void Dog::DogPrivateFunction()
{
std::cout << "In DogPrivateFunction()" << std::endl;
}
BaseFactory.h
#ifdef _WIN32
#include "Cat.h"
#elif __linux__
#include "Dog.h"
#endif
#include <memory>
class BaseFactory
{
public:
static std::unique_ptr<Base> createBase();
};
BaseFactory.cpp
#include "BaseFactory.h"
std::unique_ptr<Base> BaseFactory::createBase()
{
#ifdef __linux__
return std::unique_ptr<Base>(new Dog{});
#elif _WIN32
return std::unique_ptr<Base>(new Cat{});;
#endif
}
In the following script
#include "BaseFactory.h"
int main()
{
std::unique_ptr<Base> p = BaseFactory::createBase();
p->echo();
p->CatPrivateFunction();
return 0;
}
I'd expect the following output
In echo()
In CatPrivateFunction()
But p->CatPrivateFunction() is failing as Base.h doesn't have CatPrivateFunction() member function.
How can this be done?
Please read about upcasting and downcasting.
What you need here is to downcast the "pointer to Base" to a "pointer to Cat".
Considering that you don't know the exact type that the pointer is pointing to, you need to use dynamic_cast and check that the result is not a null pointer:
if (auto cat = dynamic_cast<Cat*>(p.get()))
cat->CatPrivateFunction();
You can't call CatPrivateFunction() without a valid pointer/reference to a Cat object. Since you only have a pointer to a Base, you would have to use dynamic_cast to test if that Base pointer is pointing at a Cat or not, and if so then you can call CatPrivateFunction() on it, eg:
#include "BaseFactory.h"
#include "Cat.h"
int main()
{
std::unique_ptr<Base> p = BaseFactory::createBase();
p->echo();
Cat *c = dynamic_cast<Cat*>(p.get());
if (c)
c->CatPrivateFunction();
return 0;
}
I already saw many answers how to create (e.g.) A class with an object B b and a B class with an object A a
like:
B:
class A;
class B{
A& a;
};
A:
class A{
B b;
};
but if I want to call a function from A in B I got: Invalid use of incomplete type 'class A'
What can I do? I think I know why the compiler say that, but I don't know how to fix it.
Here my latest Code:
Main.cpp:
#include "mainclass.h"
int main()
{
MainClass mainClass;
mainClass.print();
return 0;
}
MainClass.h:
#ifndef MAINCLASS_H
#define MAINCLASS_H
#include <iostream>
#include "subclass.h"
class MainClass
{
SubClass sub;
public:
void print() { sub.print(); }
void printTest() { std::cout << "test" << std::endl; }
};
#endif
SubClass.h:
#ifndef SUBCLASS_H
#define SUBCLASS_H
class MainClass;
class SubClass
{
MainClass* main;
public:
void print() { main->printTest(); }
protected:
private:
};
#endif
The main problem with your code is that the definition of MainClass and SubClass are mutually dependent, therefore the use of the header guards will forbid the inclusion of both header files in the same translation unit (i.e. the union of a cpp file and the all the header files included.)
The forward declaration of class MainClass in subclass.h could solve this problem, since the SubClass::main is a pointer (check the PIMPL idiom), but since you have included the implementation of the class methods in the in the header files, the compiler fails when the SubClass::print() method makes a reference to MainClass::printTest() because it knows nothing about the class MainClass except the fact that it is defined somewhere else.
On the other hand, changing the forward declaration with the explicit inclusion of mainclass.h in subclass.h is not a solution, because of the header guards, as said above.
The simple solution is to split the declaration and the implementation of you classes in .h and .cpp files. If you do so, the compiler will work on multiple translation units: one for the mainclass.cpp, one for the subclass.cpp and one for the main.cpp. When processing the subclass.cpp translation unit, the compiler will be able to include the file mainclass.h and will have the complete definition of MainClass to "see" that a MainClass::printTest() method exists.
Here is the mainclass.h:
#ifndef MAINCLASS_H
#define MAINCLASS_H
#include <iostream>
#include "subclass.h"
class MainClass
{
SubClass sub;
public:
void print();
void printTest();
};
#endif
the mainclass.cpp file:
#include <iostream>
#include "mainclass.h"
void MainClass::print()
{
sub.print();
}
void MainClass::printTest()
{
std::cout << "test" << std::endl;
}
The subclass.h file:
#ifndef SUBCLASS_H
#define SUBCLASS_H
class MainClass;
class SubClass
{
MainClass* main;
public:
void print();
};
#endif
the subclass.cpp:
#include "mainclass.h"
//#include "subclass.h" // already included with the previous line
void SubClass::print()
{
main->printTest();
}
and finally the main.cpp:
#include "mainclass.h"
int main()
{
MainClass mainClass;
mainClass.print();
return 0;
}
This will compile and will apparently work, because it will print the string "test" even if the main pointer is not initialized, and points to an undefined memory area.
This happens because the printTest method does nothing but producing a side effect, i.e. printing on screen. Indeed it does not access to any data member of the MainClass through the this pointer, and therefore you have no memory access violation. Indeed, invoking a method on a not instantiated pointer is an undefined behavior, so it would be better to avoid it, as well as cyclic dependencies.
You can't call a function (MainClass::printTest) that does not exist yet.
You can declare the function inside the SubClass, but define it after you have the MainClass definition.
#include <iostream>
class MainClass;
class SubClass
{
MainClass* main;
public:
void print();
protected:
private:
};
class MainClass
{
SubClass sub;
public:
void print() { sub.print(); }
void printTest() { std::cout << "test" << std::endl; }
};
void SubClass::print() { main->printTest(); }
int main()
{
MainClass mainClass;
mainClass.print();
return 0;
}
Avoid creating function bodies in H files and put the function body into Cpp file.
MainClass.h:
#ifndef MAINCLASS_H
#define MAINCLASS_H
#include <iostream>
#include "subclass.h"
class MainClass {
SubClass sub;
public:
void print();
void printTest();
};
#endif
MainClass.cpp:
#include <iostream>
#include "mainclass.h"
void MainClass :: print () { sub.print(); }
void MainClass :: printTest() {std::cout << "test" << std::endl; }
SubClass.h
#ifndef SUBCLASS_H
#define SUBCLASS_H
#include "mainclass.h"
class SubClass
{
MainClass* main;
public:
void print();
protected:
private:
};
#endif
SubClass.cpp
#include "mainclass.h"
#include "subclass.h"
void SubClass::print ()
{
main->printTest();
}
you can actually #include "mainclass.h" in your subclass.h because it is guarded by #ifdef
You have a design problem:-
How come in SubClass.h compiler will know class MainClass has a method printTest so that it can link to it as you did not included the header file for the definition of MainClass
Another problem is you can not even include MainClass.h in SubClass.h because you are reference to SubClass sub; in it.
MainClass* main; pointer main never initialized and hence this statement void print() { main->printTest(); } is also wrong here.
I need to call init(int* iNumber) function which is derived from the base class.
BaseClass.h
#pragma once
#include "stdafx.h"
template <class T>
class BaseClass
{
public:
BaseClass() {}
virtual ~BaseClass() {}
virtual void init(T* object) = 0;
};
ChildClass.h
#pragma once
#include "BaseClass.h"
class ChildClass : public BaseClass<int>, public BaseClass<float>
{
public:
ChildClass() {}
virtual ~ChildClass() {}
};
ChildClassImpl.h
#pragma once
#include "ChildClass.h"
class ChildClassImpl : public ChildClass
{
public:
ChildClassImpl();
virtual ~ChildClassImpl();
private:
void init(int* iNumber) override;
void init(float* fNumber) override;
};
ChildClassImpl.cpp
#include "stdafx.h"
#include <iostream>
#include "ChildClassImpl.h"
ChildClassImpl::ChildClassImpl(){}
ChildClassImpl::~ChildClassImpl(){}
void ChildClassImpl::init(int* iNumber)
{
std::cout << "Integer constructor: " << *iNumber << std::endl;
}
void ChildClassImpl::init(float* fNumber)
{
std::cout << "Float constructor: " << *fNumber << std::endl;
}
MainClass
#include "stdafx.h"
#include <iostream>
#include "ChildClassImpl.h"
using namespace std;
int main()
{
ChildClass* childClass = new ChildClassImpl();
int x = 10;
childClass->init(&x);
cout << "Test" << endl;
getchar();
return 0;
}
At compile time this is gives the error
Severity Code Description Project File Line Error
(active) "BaseClass<T>::init [with T=int]" is
ambiguous ConsoleApplication4 d:\Learning\ConsoleApplication4\ConsoleApplication4\ConsoleApplication4.cpp 14
What am I doing wrong here? How could I fix it with minimal changes?
This code fails because C++ performs name lookup before overload resolution and access control check. That is first step would be to determine to which class scope init belongs to. And in this case result would be ambiguous because init could refer to either BaseClass<int>::init or BaseClass<float>::init. Introducing an extra using declaration will bring both of those functions into ChildClass scope:
class ChildClass : public BaseClass<int>, public BaseClass<float>
{
public: using BaseClass<int>::init;
public: using BaseClass<float>::init;
So name lookup will determine that init refers to ChildClass::init and compiler will proceed to overload resolution.
Alternatively you can perform a cast (which is definitely not as convenient):
static_cast<BaseClass<int> *>(childClass)->init(&x);
I want to create a program which behaves differently depending on a facultative additional source code file to compilation (where some people might add some differing functionality). I thought about function overloading, similar to the (non-compilable) following code:
file1.cpp:
#include <iostream>
#include <string.h>
using namespace std;
class base {
public:
void ausgeb() { cout<<"here output base"<<endl; }
};
class derive: public base;
int main(int argc, char** argv)
{
derive beisp;
beisp.ausgeb();
}
file2.cpp:
#include <iostream>
#include <string.h>
using namespace std;
class base;
class derive : public base
{
public:
void ausgeb() { cout<<"here output derive"<<endl; }
};
Now I wished that:
g++ -o o1 file1.cpp file2.cpp
and
g++ -o o2 file1.cpp
should produce executable files with differing output.
Might there be a possibilty to meet that need?
This solution is gcc specific, if you switch compiler, it most probably won't work any more...
file1.cpp:
#include <iostream>
void printOut() __attribute__((weak));
void printOut()
{
::std::cout << "weak" << ::std::endl;
}
int main(int, char*[])
{
printOut();
return 0;
}
file2.cpp:
#include <iostream>
void printOut()
{
::std::cout << "strong" << ::std::endl;
}
More advanced (left out printOut implementations):
file1.h:
class Base
{
virtual void printOut();
}
file1.cpp
#include "file1.h"
Base& getInstance() __attribute__((weak));
Base& getInstance()
{
static Base theInstance;
return theInstance;
}
int main(int, char*[])
{
Base& instance = getInstance();
instance.printOut();
}
file2.cpp:
#include "file1.h"
class Derived : public Base
{
virtual void printOut();
}
Base& getInstance()
{
static Derived theInstance;
return theInstance;
}
More general solution, via defining a preprocessor symbol:
file1.h:
class Base
{
virtual void printOut();
}
file1.cpp
#include "file1.h"
#ifdef USE_DERIVED
#include "file2.h"
#endif
void Base::printOut()
{
}
int main(int, char*[])
{
#ifdef USE_DERIVED
Derived instance;
#else
Base instance;
#endif
instance.printOut();
}
file2.h:
#include "file1.h"
class Derived : public Base
{
virtual void printOut();
}
file2.cpp:
void Derived::printOut()
{
}
and compile with g++ file1.cpp in one case and g++ -DUSE_DERIVED file1.cpp file2.cpp in the other one.
In my C++ program I have separate .h and .cpp files and everything is working so far except when I want to use a base class constructor for a derived class. It is working but only if I put the function definition if the class deceleration.
Here's the working code for the .h file.
#include <iostream>
using namespace std;
class property
{
public:
property();
property(const property & src);
property(int src);
~property();
virtual int disp() const = 0;
int get_ownable();
private:
protected:
int ownable;
};
class rr : public property
{
public:
rr();
rr(const rr & src);
rr(int src):property(src)
{cout << "\nderived class was called\n";};
~rr();
virtual int disp() const;
private:
protected:
};
The imp.cpp (implementation) file is
#include "head.h"
#include <iostream>
using namespace std;
//property class implimentations
property::property()
{
ownable = 0;
}
property::property(const property & src)
{
ownable = src.ownable;
}
property::property(int src)
{
ownable = src;
cout << "\nparent class called\n";
}
property::~property()
{
}
int property::get_ownable()
{
return ownable;
}
rr::rr()
{}
rr::rr(const rr & src)
{
ownable = src.ownable;
}
/*
rr::rr(int src):property(src)
{
cout << "\nderived class was called\n";
}
*/
rr::~rr()
{
}
int rr::disp() const
{
}
There is other code but it is working fine and not connected to this. The output is
parent class called
derived class was called
So that works just fine but if I un-comment out the function in the .imp file and remove the declaration in the .h
rr(int src):property(src);
I get the error
head.h: IN constructor 'rr::rr(int)':
head.h 113: error: expeted '{' at end of input
imp.cpp: at global scope:
imp.cpp:348:error: redefiniton of 'rr::rr(int);
head.h.113: error: 'rr::rr(int); previousle defined here
All the examples I can find on line of how to do this do it with all the functions defined in the class declaration. I can't find any examples of how to do it with 2 files. Can anyone tell me how to define the base class constructor call in a separate file?
I am on a Linux system using g++ compiler.
Like this
BaseClass.h
#pragma once
class BaseClass {
public:
BaseClass(int a);
private:
int a_private;
};
BaseClass.cpp
#include "BaseClass.h"
#include <iostream>
using std::cout;
using std::endl;
BaseClass::BaseClass(int a) {
cout << "Base class constructor called" << endl;
this->a_private = a;
}
Derived.h
#pragma once
#include "BaseClass.h"
class Derived : public BaseClass {
public:
Derived(int a);
private:
int a_private;
};
Derived.cpp
#include "Derived.h"
#include <iostream>
using std::cout;
using std::endl;
Derived::Derived(int a) : BaseClass(a) {
cout << "Derived class constructor called" << endl;
this->a_private = a;
}
main.cpp
#include "BaseClass.h"
#include "Derived.h"
int main() {
Derived d(2);
return 0;
}
Compiling with the command
g++ main.cpp Derived.cpp BaseClass.cpp and running will result in the following output
Base class constructor called
Derived class constructor called
As mentioned in the comments (credits #IgorTandetnik), initializer lists should be used only in the implementation file. Not in the header file (provided the class is not templated).