Google c++ style has the following. I don't understand why forward declaration will call f(void*).
It can be difficult to determine whether a forward declaration or a full #include is needed. Replacing an #include with a forward declaration can silently change the meaning of code:
// b.h:
struct B {};
struct D : B {};
// good_user.cc:
#include "b.h"
void f(B*);
void f(void*);
void test(D* x) { f(x); } // calls f(B*)
If the #include was replaced with forward decls for B and D, test() would call f(void*).
Consider the two cases individually. By replacing the #include with the header's content, we first have :
struct B {};
struct D : B {};
void f(B*) {}
void f(void*) {}
void test(D* x) { f(x); }
There are two possible overloads. Since D inherits from B then D* is implicitly convertible to B*. Out of B* and void* the first is a better match so that overload is chosen. But in the case of a forward declared B and D :
struct B;
struct D;
void f(B*) {}
void f(void*) {}
void test(D* x) { f(x); }
D is not known to inherit from B so there is no implicit conversion possible from D* to B*. The only matching overload is f(void*).
Related
I have the following template class:
// A.hpp
class A_data {
public:
int foo = 1;
virtual ~A_data() = default;
};
template <class C = A_data> class A {
public:
int foo() const; // Not implemented here
A() { d = new C; }
~A() { delete d; }
C* d;
};
I implement the default instance of A:
// A.cpp
#include "A.hpp"
// Template source implementation
template <> int A<A_data>::foo() const { return d->foo; }
Now, I can use the class with the default instance:
// main.cpp
#include <iostream>
#include "A.hpp"
int main() {
A a;
std::cout << a.foo(); // Prints 1
}
However, suppose I want to create a class which inherits A, along with its own data class which inherits A_data, like so:
// A.hpp
class B_data : public A_data {
public:
int bar = 2;
virtual ~B_data() = default;
};
// Template here is in case something needs to inherit B, like in A.
template <class C = B_data> class B : public A<C> {
public:
int bar() const; // Not implemented here, just like A::foo.
};
// A.cpp
template <> int B<B_data>::bar() const { return d->bar; }
This results in the following problem:
#include <iostream>
#include "A.hpp"
int main() {
B b;
std::cout << b.bar(); // Works fine, prints 2
std::cout << b.foo(); // Linker error: no implementation of A<B_data>::foo!
}
As you can probably glean from the example, the intent is to have a class with its own data container (in this case A and A_data), such that other classes can inherit it (B), and can optionally choose to expand the data container by inherting the parent's container (B_data).
I can get around this problem by defining the implementation in A.hpp, but in this case I don't want to provide multiple interfaces of A other than A_data and its derived classes. If I really wanted to, I could implement each instance in A.cpp, but it adds nothing of value since the implementation itself is invariant.
My expectation was that B<B_data> would be able to "know" about A<A_data> and use A <A_data>::foo, since B inherits from A. Obvously, since B<B_data> and B<A_data> are not related, this is not the case -- but can it be?
Can I achieve this "expanding class" interface without exposing the implementation in the header? If not, is there a better alternative that would still allow me to maintain this simple interface?
Part of the reason templates seemed to be appealing here as opposed to regular class inheritence is because they allow to automatically dereference the correct container data without doing any type of pointer casts. Example with regular classes:
#include "A.hpp"
int A::foo() const { return d->foo; }
int B::bar() const { return d->bar; } // Compiler error: No member 'bar' in 'A_data'
If you want to stick to templates, you can implement this 'mirrored inheritance' as follows: make B<B_data> inherit from A<A_data> instead of A<B_data> by declaring in B_data (or other possible template argument types) an alias base to a whatever type you want to consider base for your purposes (it's ambiguous in general, since there may be many bases of a class) and making B<C> inherit from A<C::base>. Then, for B<C>, since d is of type C::base*, it can still hold a pointer to C which is derived from C::base (assuming C::base is set adequately and is an actual base). But in this case, we need to provide a custom default constructor in B so that it constructs C object for d, not C::base which would happen if default constructor for A<C::base> would be called by implicitly defaulted default constructor of B<C> (note that there's no need to provide destructor since delete d from A<C::base>'s destructor will work correctly if C::base has virtual destructor). Then, since inside B<C> we know how we constructed the object d points to, we can safely assume we know its dynamic type and access it through static_cast-ed pointer (for safety you could e.g. add dynamic_cast-check inside assert for Debug-builds check).
Example implementation (see also comments, in particular for some changes of other aspects of your code):
// A.hpp
class A_data {
public:
int foo = 1;
virtual ~A_data() = default;
};
template <class C = A_data> class A {
public:
int foo() const;
A() { d = new C; }
// 'virtual' is not strictly needed in our particular case since we don't delete B
// through A*, but still it is safer and best practice with it than without
virtual ~A() { delete d; }
C* d;
};
class B_data : public A_data {
public:
using base = A_data;
int bar = 2;
// virtual ~B_data() = default; implicitly defaulted and virtual
};
template <class C = B_data> class B : public A<typename C::base> {
public:
B() { this->d = new C; } // 'this' needed to trigger dependent name lookup
int bar() const;
};
// A.cpp
#include "A.hpp"
template <> int A<A_data>::foo() const { return d->foo; }
template <> int B<B_data>::bar() const { return static_cast<B_data*>(d)->bar; }
// main.cpp
#include <iostream>
#include "A.hpp"
int main() {
B b;
std::cout << b.bar();
std::cout << b.foo();
}
Note also that if you want to use different template arguments C, you may want to avoid code duplication in specialization definitions in A.cpp. There, you can define your templated functions usually (not as specializations), but to force instantiations use explicit template instantiations. E.g. suppose there's B_data_2 class defined like this:
// in A.hpp
class B_data_2 : public A_data {
public:
using base = A_data;
int bar = 3;
};
It also has bar public data member, but with different default initializer. Now we can add another specialization for B<B_data_2>::bar() to A.cpp, but it will be basically the same as B<B_data>::bar(), so code duplication arises:
// in A.cpp
template <> int A<A_data>::foo() const { return d->foo; }
template <> int B<B_data>::bar() const { return static_cast<B_data*>(d)->bar; }
template <> int B<B_data_2>::bar() const { return static_cast<B_data_2*>(d)->bar; }
Instead, if we replace specializations with general definitions followed by explicit instantiation definitions of methods, we have:
// in A.cpp
template<class C> int A<C>::foo() const { return d->foo; }
template int A<A_data>::foo() const;
template<class C> int B<C>::bar() const {
return static_cast<C*>(this->d)->bar; // Again 'this' to enable dependent name lookup
}
template int B<B_data>::bar() const;
template int B<B_data_2>::bar() const;
This obviously scales better, but to avoid doing explicit instantiation for every member function of the same specialization, we can do even better - explicitly instantiate whole class specializations, which will, in particular, automatically instantiate all (non-templated) member functions of that specializations:
// in A.cpp
template<class C> int A<C>::foo() const { return d->foo; }
template<class C> int B<C>::bar() const {
return static_cast<C*>(this->d)->bar; // Yet again 'this' to enable dependent name lookup
}
template class A<A_data>;
template class B<B_data>;
template class B<B_data_2>;
Now we can test and see that it compiles and works:
// main.cpp
#include <iostream>
#include "A.hpp"
int main() {
B b;
B<B_data_2> b_2;
std::cout << b.bar() << b.foo() << std::endl; // 21
std::cout << b_2.bar() << b_2.foo() << std::endl; // 31
}
Putting implementation in header would be fine in your case, and you don't need specialization:
class A_data {
public:
int foo = 1;
virtual ~A_data() = default;
};
template <class C = A_data>
requires(requires(C c) { c.foo; } ) // Possibly, in C++20
class A
{
public:
int foo() const { return d->foo; }
A() = default;
std::unique_ptr<C> d = std::make_unique<C>();
};
class B_data : public A_data {
public:
int bar = 2;
virtual ~B_data() = default;
};
// Template here is in case something needs to inherit B, like in A.
template <class C = B_data>
requires(requires(C c) { c.foo; c.bar;} ) // Possibly, in C++20
class B : public A<C> {
public:
int bar() const { return this->d->bar; }
};
#include <iostream>
int main() {
B b;
std::cout << b.bar();
std::cout << b.foo();
}
Demo
The problem is that you've explicitly specialized foo for the template argument A_data instead of B_data.
To solve this just change the explicit specialization to be for the argument B_data as shown below:
A.cpp
#include "A.hpp"
//----------------vvvvvv---------------------------------->changed from A_data to B_data
template <> int A<B_data>::foo() const { return d->foo; }
template <> int B<B_data>::bar() const { return d->bar; }
main.cpp
#include <iostream>
#include "A.hpp"
int main() {
B b;
std::cout << b.bar(); // Works fine, prints 2
std::cout << b.foo(); // WORKS FINE, prints 1
}
Working demo
The output of the above modified program is:
21
Explanation
B is instantiated with B_data and so it inherits from A<B_data>. Note carefully that it inherits from A<B_data> and not A<A_data>. This means that foo's implementation for A<B_data> should be provided. But you never provided foo's implementation for A<B_data> because what you actually provided was implementation of foo for A<A_data> and hence the error. Thus by changing A_data to B_data as shown in the modified code above, we get rid of the error.
Consider the following short but multifile example:
// ************************** unit.h **************************
#pragma once
#include <memory>
struct S;
struct B {
B(int) {};
virtual ~B() {};
};
struct D : B {
D(int);
~D() override;
std::unique_ptr<S> p;
};
// ************************** unit.cpp **************************
#include "unit.h"
struct S {};
D::D(int i) : B(i) {}
D::~D() = default;
// ************************** prog.cc **************************
#include "unit.h"
int main()
{
D d(42);
}
There are two classes with inheritance: base B and derived D. D class contains a unique_ptr member definition with only declared class S. To make this scheme work I need to define both constructor and destructor of class D out-of-line (i.e. implemented in unit.cpp, where the full definition of S is visible).
The question: is it possible to use the using B::B; declaration in the D class inherit the B's constructors to prevent writing manually D::D(int i) : B(i) {}, but make this inheritance out-of-line in order to prevent compilation error?
error: invalid application of 'sizeof' to an incomplete type 'S'
is it possible to use the using B::B; declaration in the D class inherit the B's constructors to prevent writing manually D::D(int i) : B(i) {}
It is possible.
Along with the forward declaration of struct S also declare its deleter:
struct S;
struct SDeleter { void operator()(S*) const; }; // Defined elsewhere.
And then:
struct D : B {
using B::B;
std::unique_ptr<S, SDeleter> p;
};
The definition of void SDeleter::operator()(S*) const must be provided in another translation unit (.cc) that has access to the definition of S.
I have 5 classes (A,B,C,D,E), each of which will have their own class and header files.
class A{};
class B
{
B(A&a);
};
class C
{
C(B&b);
};
class D:public A
{};
class E:public D
{
vector<C*> vc;
};
Forward declaration will not work because I also have a lot of sharepointers being used in each of those classes.
You can use forward declarations for shared pointers as well, you just need to forward declare a destructor function object as well.
Header:
struct A;
shared_ptr<A> create_A();
Impl:
struct A { ... };
struct A_destroyer { void operator()(A *p) { delete p; } };
shared_ptr<A> create_A() { return shared_ptr<A>(new A(), A_destroyer()); }
Each class can declare a destructor and define that destructor in a source including the header for the appropriate type destructed by unique/shared pointer. Than a simple forward of that type in the header will do it.
#include <memory>
// header B
struct A;
struct B {
~B();
std::shared_ptr<A> a;
};
// header A
struct A {};
// source B
#include "a"
#include "b"
B::~B() {}
I'm having a problem compiling with circular dependencies. I did some research, and people recommended using a forward declaration. I'm still having a problem with that because the class that has a forward declaration is using methods from the forwarded class. This causes the compiler to give me the error "Class A has incomplete field b". How can I get around the circular dependency where A requires B, and B requires A?
A.h:
#ifndef A_H_
#define A_H_
#include <iostream>
//#include "B.h"
class A
{
class B;
private:
B b;
public:
A();
~A();
void method();
};
#endif
A.cpp:
#include <iostream>
#include "A.h"
A::A()
{
}
A::~A()
{
}
void A::method()
{
b.method();
}
B.h:
#ifndef B_H_
#define B_H_
#include <iostream>
//#include "A.h"
class B
{
class A;
private:
A a;
public:
B();
~B();
void method();
};
#endif
B.cpp:
#include <iostream>
#include "B.h"
B::B()
{
}
B::~B()
{
}
void B::method()
{
a.method();
}
Your classes cannot work. Every A contains a B, which contains an A, which contains a B, etc., ad infinitum.
This will not work as you have constructed it as A requires full knowledge of the size of B and B requires the same of A, which is only given by seeing the full declaration.
The following is not valid:
class B;
class A {
B b;
};
Why? How much space do we allocate for an instance of A? sizeof(A) = sizeof(B) = undefined There is a workaround, however:
class B;
class A {
B* b_ptr;
B& b_ref;
};
This is perfectly valid, since the pointer and reference's size are known, regardless of the type they point to.
In at least one case (either A or B) you have to remove the dependence on the complete type. For example, below I've removed the need for A to have the complete type of B within the A.h header file:
// A.h
class B;
// B used as a reference only, so the complete type
// is not needed at this time
class A
{
public:
A(B& b) : b_(b) {}
void method();
private:
B& b_;
};
// A.cpp
// B is used, and the complete type is required
#include "B.h"
void A::f()
{
b.method();
}
You could try to replace one of the member by a pointer to the other class :
class B;
class A
{
private:
B* b;
public:
A();
~A();
void method();
};
Im trying to make class A a friend of class B.
class B;
class A{
public:
void show(const B&); // ##1## but this one works fine
B ob;// error incomplete type
};
class B{
public:
int b;
B():b(1){}
friend class A;
};
so my question why it's incomplete type? I thought that when I did class B it's like a prototype of a function which tell the compile there is a definition somewhere in the code.
also in the code above at ##1## why this is possible ?
No, that's a forward declaration and does not define a full type. You'll need to have a full definition of B before A, if you want to keep the member as an object and not pointer.
One of the reason for this is that the size of the class B must be known to A, since A's size depends on B.
I suggest you #include "B.h" in A.h.
EDIT: clarification:
struct A;
struct B
{
A foo();
void foo(A);
void foo(A&);
void foo(A*);
A* _a;
A& __a;
A a; // <--- only error here
};