How to forward declare a custom constructor? - c++

Note: I have found the issue with how my Xcode was compiling the below and it appears unrelated to the topic discussed herein. When I have more details I will provide them here.
I recommend voting to close my question as "too localized" since it was an Xcode problem, unrelated to the c++ code itself. Many thanks for the help all the same as I did learn from the answers.
The below question (now answered and resolved) was caused by a confusing exclusion of a file from the Xcode target, thus there were no compiler errors even though the file had problems.
I have a pure virtual interface and want to define its factory method, which returns a subclass of this interface. This works fine:
struct MyVirt{
...all virtual stuff
};
class SubVirt; //forward declaration allows factory:
MyVirt*CreateClass(){
return new SubVirt;
}
Update: Some of the comments say that forward declare is not enough to achieve the above, but that's not correct. You can accomplish the above fine without the full definition of the SubVirt class.
Now, what I want to do is have a custom constructor that takes arguments. As such:
MyVirt*CreateClass(){
return new SubVirt(arg 1, etc);
}
The problem is that a class forward declaration is no longer sufficient. It needs to see the class definition or its header. This means I can either move the factory method to the file where SubVirt is defined, or I have to include that file in the above file, which creates a circular dependency.
Is there a way to forward declare the custom constructor instead? That would make it all much simpler.

Your CreateClass function looks odd, you miss () in function definition. Should be like this:
MyVirt* CreateClass()
{
return new SubVirt(arg 1, etc);
}
When return a pointer, compiler needs to know the concrete type and constructor, so forward declare is not enough.
What you could do is:
in header file: forward declare SubVirt and CreateClass function
cpp file: include MyVirt.h and define CreateClass function

Separate declaration from implementation, like everyone does.
MyVirt.h:
struct MyVirt{
...all virtual stuff
};
MyVirt.cpp:
#include "MyVirt.h"
Implementation of MyVirt
SubVirt.h:
#include "MyVirt.h"
struct SubVirt : MyVirt {
...all SubVirt stuff
};
SubVirt.cpp:
#include "SubVirt.h"
Implementation of SubVirt
Factory.h:
struct MyVirt;
MyVirt *CreateClass();
Factory.cpp:
#include "SubVirt.h"
MyVirt *CreateClass() { return new SubVirt() }

This can be accomplished by separating the declaration and implementation.
The key here is to put the definition/implementation above the includes. Suppose you want to separate the classes A and B create two files like the following:
A.hpp
#ifndef A_HPP
#define A_HPP
struct B; // fwd. decl.
struct A {
int v;
A(int v) {
this->v = v;
}
B* createB();
};
#include "B.hpp"
A* B::createA() {
return new A(v);
}
#endif A_HPP
B.hpp
#ifndef B_HPP
#define B_HPP
struct A; // fwd. decl.
struct B {
int v;
B(int v) {
this->v = v;
}
A* createA();
};
#include "A.hpp"
B* A::createB() {
return new B(v);
}
#endif // B_HPP
main.hpp
#include <A.hpp>
#include <B.hpp>
#include <iostream>
int main(int argc, char *argv[]) {
A a(42);
std::cout << a.createB()->createA()->v << std::endl;
return 0;
}
You are of course free to move the implementation into a cpp file instead. This is only the basic recipe which shows how circular dependencies can be solved even for templated classes and functions.
http://codepad.org/IsBzQANX

Related

Is pimpl idiom better than using always unique_ptr as member variables?

In my workplace we have this convention: almost every class (with very few exceptions) is implemented with unique_ptrs, raw pointers or references as member variables.
This is because of compilation times: in this way you just need a forward declaration for the class in your header file and you only need to include the file in your cpp. In addition if you change the .h or the .cpp of a class that you are including with unique_ptr you will not need to recompile.
I think that this pattern has at least these downsides:
it forces you to write your own copy constructors and assignment operators and you have to manage each variable individually, if you want to keep the semantic of copying.
the syntax of the code become very cumbersome, for example you will have std::vector<std::unique_ptr<MyClass>> instead of the much more simple std::vector<MyPimplClass>.
the constness of the pointer is not propagated to the pointed object, unless you use std::experimental::propagate_const, which I cannot use.
So it came to my mind to propose to use the pImpl idiom for the classes being included as a pointer instead of using pointers everywhere. In this way I thought we can have the best of both worlds:
Faster compile times: pimpl reduces compilation dependencies
To write your copy constructor and your copy assignment operator you just do this:
A::A(const A& rhs) : pImpl(std::make_unique<Impl>(*rhs.pImpl)) {}
A& A::operator=(const A& rhs) {
*pImpl = *rhs.pImpl;
return *this;
}
The constness is propagated to the member object.
At this point I had a discussion with my coworkers, they are arguing that pImpl is that it is not better than using pointers everywhere because of the following:
It reduces compilation dependencies less than using pointers, because if you are using pImpl you have to recompile the classes that includes your pImpl class when you change your public interface: if you were using just a pointer instead of the pImpl class you won't need to recompile even when changing the header file.
Now I am a little confused. I think that our actual convention is not really better than pImpl but I am not able to argue why.
So I have some questions:
Is the pImpl idiom a good alternative in this scenario?
Are there other downsides of the pattern we are using, except the ones that I mentioned?
Edit:
I am adding some examples to clarify the two approaces.
Approach with unique_ptr as member:
// B.h
#pragma once
class B {
int i = 42;
public:
void print();
};
// B.cpp
#include "B.h"
#include <iostream>
void B::print() { std::cout << i << '\n'; }
// A.h
#pragma once
#include <memory>
class B;
class A {
std::unique_ptr<B> b;
public:
A();
~A();
void printB();
};
// A.cpp
#include "A.h"
#include "B.h"
A::A() : b{ std::make_unique<B>() } {}
A::~A() = default;
void A::printB() { b->print(); }
Approach with pImpl:
// Bp.h
#pragma once
#include <memory>
class Bp {
struct Impl;
std::unique_ptr<Impl> m_pImpl;
public:
Bp();
~Bp();
void print();
};
// Bp.cpp
#include "Bp.h"
#include <iostream>
struct Bp::Impl {
int i = 42;
};
Bp::Bp() : m_pImpl{ std::make_unique<Impl>() } {}
Bp::~Bp() = default;
void Bp::print() { std::cout << m_pImpl->i << '\n'; }
// Ap.h
#pragma once
#include <memory>
#include "Bp.h"
class Ap {
Bp b;
public:
void printB();
};
// Ap.cpp
#include "Ap.h"
#include "Bp.h"
void Ap::printB() { b.print(); }
Main:
// main.cpp
#include "Ap.h"
#include "A.h"
int main(int argc, char** argv) {
A a{};
a.printB();
Ap aPimpl{};
aPimpl.printB();
}
Moreover I want to be more precise when I say that the first approach we don't need to recompile, this is inaccurate. It is true that we need to recompile less files:
If we change B.h we need to recompile only A.cpp, B.cpp.
If we change Bp.h we need to recompile Ap.cpp, Bp.cpp and main.cpp
After a while I have a broader understanding of the problem and finally I can answer to my own question.
It turned out that what I was saying was not completely correct.
In fact in the code below only Bp class is pImpl. If we change Ap to be pImpl aswell we obtain that, if we change Bp.h we need to recompile only Ap.cpp, Bp.cpp, which is the same of the corresponding solution with unique_ptrs.
Said that, I think I can say that the solution with pImpl seems in general better than the solution with unique_ptrs (we just have to pImpl the correct classes!).
For this reason we decided to switch to pImpl idiom as default for our classes.

Cyclic dependency and inheritance compilation error on c++

I have a problem in C++ that involves circular dependencies and inheritance.
I have implemented the design in parts and I will use pesudocode to ilustrate where the problem happens.
The first part is:
//app.h
include rel.h
class Rel; // forward declaration
class App {
shared_ptr<Rel> //member variable
}
//rel.h
include app.h
class App; //forward declaration
class Rel {
shared_ptr<App> //member variable
}
Until here, the program compiles without warnings
Then, I want to add inheritance as follows:
//app.h
include rel.h
include drel.h
class Rel; // forward declaration
class DRel // forward declaration
class App {
shared_ptr<Rel> //member variable
shared_ptr<DRel> //member variable
}
//rel.h (the same as before)
include app.h
class App; //forward declaration
class Rel {
shared_ptr<App> //member variable
}
//drel.h
include app.h
include rel.h
class App; //forward declaration
class DRel: Rel { // compile error here: expected class name before { token
shared_ptr<App> //member variable
}
As you see, the compiler throws "expected class name before { token" which means that Rel is not resolved, but why the first code without inheritance works and the second one doesn't? How can I fix that? Is that a "wrong" pattern?
I am using c++14
I know there are a lot of questions regarding the issues I am having, but I can't find the answer to my specific problem. Maybe I don't see it...
Since all the variables you declare do not need to know the space occupied by App, Rel and DRel, you don't even need to #include the headers in question, you just have to forward declare the name as you do.
So you have you .h with
class A;
class B;
class C {
std::shared_ptr<A> ptra;
std::shared_ptr<B> ptrb;
};
And then your .cpp with
#include "A"
#include "B"
C::C() { ... }
The original headers files needed to be guarded by #ifdefs like this:
#ifndef CYCLIC_DEPENDECY_1
#define CYCLIC_DEPENDECY_1
#include "cyclic_dependency2.h"
class Rel; // forward declaration
class App {
std::shared_ptr<Rel> test; //member variable
};
#endif
#ifndef CYCLIC_DEPENDECY_2
#define CYCLIC_DEPENDECY_2
#include "cyclic_dependency1.h"
class App; //forward declaration
class Rel {
std::shared_ptr<App> test;//member variable
};
#endif
#include <iostream>
#include <memory>
#include "cyclic_dependency2.h"
class Rel; // forward declaration
class DRel; // forward declaration
class DRel: Rel {
std::shared_ptr<App> test ;//member variable
};
main()
{
}

invalid use of incomplete type error

This is simplified code just to show my question:
main.cpp
#include "one.hpp"
#include <iostream>
int main(){
One one;
std::cout << one.two->val;
}
one.hpp:
struct Two; <- forward declare Two
struct One{
One();
~One() { delete two;}
Two* two;
};
one.cpp
#include "one.hpp"
struct Two{
int val;
};
One::One(): two(new Two()) {}
When compiling this I get error invalid use of incomplete type 'struct Two'.
I assume that since Two is incomplete type I just cannot refer to its fields...
I am wondering is there any way to hide Two implementation in one cpp file and use it in another cpp file using this kind of forward declaration? Question comes from creating API where I would like to hide implementation on some classes.
You cannot delete an object of incomplete type.
The solution is to define the destructor in one.cpp, too.
one.hpp:
struct One {
~One();
// ...
};
one.cpp:
// ...
One::~One() { delete two; }
Wikipedia: "Opaque pointers are a way to hide the implementation details of an interface from ordinary clients, so that the implementation may be changed without the need to recompile the modules using it. ":
Header file released to clients:
struct opaque;
struct interface
{
~interface();
void test();
opaque* _p;
};
Header file not released to clients:
struct opaque
{
void test();
//...
};
interface implementation file:
#include "interface.h"
#include "opaque.h"
interface::~interface()
{
delete _p;
}
void interface::test()
{
_p->test();
}
// ...
opaque implementation file:
#include "opaque.h"
void opaque::test()
{
// actual implementation
}

How to avoid #include dependency to external library

If I'm creating a static library with a header file such as this:
// Myfile.h
#include "SomeHeaderFile.h" // External library
Class MyClass
{
// My code
};
Within my own project I can tell the compiler (in my case, Visual Studio) where to look for SomeHeaderFile.h. However, I don't want my users to be concerned with this - they should be able to include my header without having to inform their compiler about the location of SomeHeaderFile.h.
How is this type of situation normally handled?
This is a classic "compilation firewall" scenario. There are two simple solutions to do:
Forward-declare any classes or functions that you need from the external library. And then include the external library's header file only within your cpp file (when you actually need to use the classes or functions that you forward-declared in your header).
Use the PImpl idiom (or Cheshire Cat) where you forward-declare an "implementation" class that you declare and define only privately (in the cpp file). You use that private class to put all the external-library-dependent code to avoid having any traces of it in your public class (the one declared in your header file).
Here is an example using the first option:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class some_external_class; // forward-declare external dependency.
class my_class {
public:
// ...
void someFunction(some_external_class& aRef); // declare members using the forward-declared incomplete type.
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
void my_class::someFunction(some_external_class& aRef) {
// here, you can use all that you want from some_external_class.
};
Here is an example of option 2:
#ifndef MY_LIB_MY_HEADER_H
#define MY_LIB_MY_HEADER_H
class my_class_impl; // forward-declare private "implementation" class.
class my_class {
private:
std::unique_ptr<my_class_impl> pimpl; // a vanishing facade...
public:
// ...
};
#endif
// in the cpp file:
#include "my_header.h"
#include "some_external_header.h"
class my_class_impl {
private:
some_external_class obj;
// ...
public:
// some functions ...
};
my_class::my_class() : pimpl(new my_class_impl()) { };
Say the external header file contains the following:
external.h
class foo
{
public:
foo();
};
And in your library you use foo:
myheader.h:
#include "external.h"
class bar
{
...
private:
foo* _x;
};
To get your code to compile, all you have to do is to forward declare the foo class (after that you can remove the include):
class foo;
class bar
{
...
private:
foo* _x;
};
You would then have to include external.h in your source file.

Compilation issue - typedefs, forward declarations, namespaces?

I'm trying to help a coworker get something compiled - essentially, he was trying to reduce dependencies for a small executable we need to make from a larger software system.
I'm not sure I can fully explain the problem as I don't completely understand it... but I'm going to show what's going on here:
Library A: File: A.h
namespace CF {
typedef sometype B;
};
Library C: File C.h
//Forward declare Class
class CF::B;
Class D {
public:
B* UseB();
};
Library C: File C.cpp
#include "C.h"
#include "A.h"
using CF::B;
B* D::UseB()
{
return new B;
}
Sorry, I know this looks a little crazy but I have tried to simplify it from the set of files that we're actually dealing with.
We're typically getting either a multiple definition error on CF::B, or when we play with the code and change it around, sometimes in the CPP file it just doesn't recognize the type of CF::B.
I guess my first question is... can I forward declare the typedef like we've tried, or is there some other way to deal with the fact that B is a typedef in CF namespace, and we don't want it to be directly included in the C.h file?
This will probably help you:
a.h:
#ifndef NAMESPACE_A
#define NAMESPACE_A
namespace A
{
class B
{
public: int i;
};
}
#endif
c.h:
#ifndef NAMESPACE_A
#define NAMESPACE_A
namespace A
{
class B;
}
#endif
class D
{
public:
A::B* UseB();
};
main.cpp:
#include "a.h"
#include "c.h"
using A::B;
B* D::UseB()
{
return new B();
}
int main(int argc, char* argv[])
{
D* d = new D();
B* b = d->UseB();
b->i = 1;
return 0;
}
... works fine for me ;)
A forward declaration would be more like
namespace CF { class B; }
The compiler cannot make anything out of CF::B unless it already knows CF to be a namespace.
You also cannot forward declare a typedef, because the compiler must know if B is a class or a built in type. Some built in types have special rules, like char* or void*.