Mutually-dependent C++ classes, held by std::vector - c++

I was curious if was possible to create two classes, each of which holds a std::vector of the other. My first guess was that it would not be possible, because std::vector requires a complete type, not just a forward declaration.
#include <vector>
class B;
class A { std::vector<B> b; };
class B { std::vector<A> a; };
I would think that the declaration of std::vector<B> would cause an immediate failure, because B has an incomplete type at this point. However, this compiles successfully under both gcc and clang, without any warnings. Why doesn't this cause an error?

T.C commented that this is actually undefined behavior which is being addressed in a change request to the standard. The rule which is violated is apparently [res.on.functions] 2.5:
In particular, the effects are undefined in the following cases: [...]
if an incomplete type (3.9) is used as a template argument when instantiating a template component, unless specifically allowed for that component.
The reason this works anyway (and the reason that it can be standardized) is two-fold:
Your program only contains type definitions; no objects are created, no functions are called, no code is generated. If we simplify it by eliminating B's definition (it's not needed) and then try to create an instance of A, it fails:
class B;
class A { std::vector<B> b; };
A a; // error: ctor and dtor undefined for incomplete type B.
What also fails, as expected, is a simple
std::vector<B> b;
The reason in both cases is that the compiler must produce code, as opposed to a mere type declaration which is only grammatically relevant.
The use of the vector type is ok also in other contexts:
typedef std::vector<B> BVec;
Class A can be defined because, as Nikolay correctly says in his answer, the size of std::vector<B>, and hence the size of A's member b, does not depend on the definition of B (because a vector holds a pointer to an array of elements, not an array proper).

This compiles and runs ok because std::vector uses pointers and not the exact definition of A or B. You could modify your example to use single instance or array in the definition of the classes like so
class B;
class A { public: B b[2]; };
class B { public: A a[2]; };
This obviously fails to compile since you're trying to use definition of the classes. And the error by the compiler would be as you're expecting
error: field ‘b’ has incomplete type ‘B [2]’
However
class B;
class A { public: B* b; };
class B { public: A* a; };
would work just like std::vector. So you don't need fully defined class to use pointer or reference to this type.
Also there is simplified example with templates
template<typename T>
struct C {
T* t;
};
class B;
class A { public: C<B> b; };
class B { public: C<A> a; };
This would also work and of course you can instantiate it
int main() {
B b;
A a;
}

It's because of template instantiation rules. At the point of A's declaration, only std::vector<B>'s interface is required to be instantiated.
Since std::vector's interface only uses pointers and references to its value type, and the specialization in your example gets instantiated but none of its functions are used, you don't get a compiler error for it.
As for why the compiler didn't generate A::A()—which would've triggered the error by calling std::vector<B>'s constructor—it's because your context only required its declaration. The compiler only needs to generate defaults for these special member functions if it sees they're used.
References
§ 14.7.1
[...] The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, scoped member enumerations, static data members and member templates[.]
§ 12
[1] [...] The implementation will implicitly declare these [special] member functions for some class types when the program does not explicitly declare them. The implementation will implicitly define them if they are odr-used.

Related

Why does ordering of class members of the user defined type matter in C++?

Case 1:
class A
{
B b; //error: identifier B is undefined
struct B
{
};
};
Case 2: Using forward declaration.
class A
{
struct B;
B b; //error: incomplete type is not allowed
struct B
{
};
};
Case 3: Definition before usage
class A
{
struct B
{
};
B b; //does not throw error
};
This need for the struct to be defined before a variable of its type can be declared as a data member is what is confusing me. From what I recall, the ordering of members in a class did not matter. So I wanted to know why this happens, and how do I get around it if I want the definition of the struct to be in the private implementation but a data member of its type to be in the public interface.
EDIT: This post clarifies why types need definition before being used as function parameters or data members. But how does one work around this limitation?
Case 1 is easy to understand, you can't use an identifier that isn't known to the compiler yet.
Case 2 is a little more subtle. There might be multiple reasons it doesn't work, but the simplest is that it needs to know the size of each member so it can calculate the offset of succeeding members and the total size of the class. It can't do that unless the full definition is known. You can use a forward declaration to have a pointer or reference to the struct, but not the struct itself.

How to prototyply declare an inherited class in C++?

I am making a project, which requires multiple classes, some of them are inherited!!
So i am using one inherited class in a main class before it's definition!
Kindly help me to how to use prototype declaration for inherited class.thanks!!
Example:
class A
{
/*data*/
};
class B:public A
{public:
void func()
{
C obj;
}
};
class C:public B
{
};`
Only functions have prototypes. What you can do with class is to forward declare it.
class MyFutureClass;
struct MyFutureStruct;
These is an incomplete classes. No, that structs in C++ are same as classes, just they have public access by default, classes have private. To make them complete you should provide definition anywhere further in code.
Incomplete class is just one possible incomplete type. The following types are incomplete types:
type void;
class type that has been declared but not defined;
array of unknown size;
array of elements of incomplete type;
enumeration type until its underlying type is determined.
Now what you can use incomplete class for?
declare a pointer variable or class field
Declare a function or method that accepts argument or returns of incomplete type, without defining it.
what you can't do with it?
Inherit incomplete class by other class
Define objects fields of incomplete type
Declare non-static class data member of incomplete type
Use incomplete class type as parameter for template
Define functions that use argument of incomplete type or
Perform implicit or explicit conversion to incomplete class, implicit or explicit, lvalue-to-rvalue conversions, standard conversion, dynamic_cast, or static_cast to pointer or reference of incomplete type, except when converting from the null pointer constant or from a pointer to void (void* always can be converted and void never is defined)
Access incomplete class' members or methods
Use new expressions that create object of incomplete type
Use it in catch-clause
Use typeid, sizeof, or alignof operator
Use arithmetic operator on pointer to incomplete class (because sizof isn't known , of course)
What it is needed for?
To avoid cyclic dependency of headers, when one class depends on existence and functionality of other
To reduce amount of headers included in single file. You can define class that got pointers and formal parameters of declared class without defining it
let's see, this is an absolutely useless example of avoid cyclic use of headers.
[class_a.h]
class B;
class A
{
B* p;
public:
A ( B& value );
};
[class_b.h]
#include "class_a.h"
class B : public A // we need complete A to inherit it
{
int a;
public:
B ( const B& );
};
[class_a.cpp]
#include "class_b.h"
// to define this constructor we need complete A, but header with complete
// definition is already included within class_b.h header
A::A ( B& val) : p( new B(val)) // we created copy of B
{
}
So, to define class A we need class B, but class B is child of class A, thus it needs complete definition of A. Conundrum? No. Thanks to forward declaration, we can define class A without defining B.
(PS. If someone reviewed code and found something impossible there, my explicit allowance to fix it is due... I'm falling asleep)

Getting "field has incomplete type" even after adding forward reference

I'm still just learning c++ and trying sort out how to have two c++ classes store instance variables of each-other. I realize that you've got to add a forward reference to do this, but I think I must still be missing something here.
class B;
class A {
public:
B b;
};
class B {
public:
A a;
};
Trying to compile this gives the error:
temp.cpp:5:5: error: field 'b' has incomplete type
B b;
^
When you use a type as member, the type must complete. In your case, you want to use B,A inside each other which is not possible.
But you could use pointer to resolve the issue:
class B;
class A {
public:
B* b; // now b is a pointer which points to B type, incomplete type B is OK
};
§ 3.9.5 Types
A class that has been declared but not defined, or an array of unknown size or of incomplete element type, is an incompletely-defined object type.43 Incompletely-defined object types and the void types are incomplete types (3.9.1). Objects shall not be defined to have an incomplete type.
You cannot do this. This is an infinite recursion: an instance of A has to include an instance (not a pointer!) of B, and an instance of B has to include an instance of A.

When do constructors of static members of template classes get called in C++?

There is plenty of information on when constructors of static members of ordinary classes are called. However, I am seeing some strange behavior with regard to template classes.
What should the output of the following program be? (Note I use printf to avoid any static initialization order fiasco complications with std::cout.)
#include <iostream>
class B {
public:
B(const std::string &s) { printf("Hello I am B from %s\n", s.c_str()); }
};
template<typename T>
class Atempl {
public:
static B b_;
};
class A {
public:
static B b_;
};
template<typename T>
B Atempl<T>::b_("Atempl");
B A::b_("A");
class C : public Atempl<int> {
};
int main(int argc, const char *argv[]) {
return 0;
}
I think the output should be:
Hello I am B from A
Hello I am B from Atempl
But with g++ 4.3 on FreeBSD 7.3 I get:
Hello I am B from A
If I add the line
template class Atempl<int>;
all is well and I get the expected output. The question is, why doesn't the declaration of class C count as an instantiation of the template
Atempl
and cause B's constructor to be called? Is this part of the standard or a bug in g++ 4.3?
In a class template, when performing implicit instantiation, the members are instantiated on demand. Since the code does not use the static member, it is not even instantiated in the whole application.
When you do an explicit intantiation, the whole class and all of its members are instantiated, and that includes the static member variable, which is then initialized and you get your expected result.
Without the explicit instantiation you could do something like B* p = &Atempl<int>::b_; (or any other use of the static member) to trigger the instantiation.
When a static member of a class template template is initialized is
unspecified. In fact, unless you actuall use the static member, it
should not be instantiated, and so never be initialized. If you
explicitly instantiate the template, you force the instantiation of all
of the members, which in turn forces the initialization (but I think
exactly when it will be initialized is still unspecified).
They are called by the C++ runtime sometime after the start of the process and before main() is called. There is no difference between 'regular' classes and class template instances. The order in which the constructors are called is undefined.

Problem with declaring Objects in C++

I have a simple code below:
class B;
class A{
B b;
};
class B{
public:
B(){
}
};
In class A's definition, I have a B-typed property. Using MS Visual Studio to compile, I've got the following error:
error C2079: 'A::b' uses undefined class 'B'
Due to some reasons, I can't put class B's definition before class A's one. Any idea?
The compiler is already telling you what's wrong : A has a member data b which is of an undefined type. Your forward declaration:
class B;
is just that : a declaration, not a definition. Since class A contains an instance of B directly (not just a pointer to B), the compiler needs to know the exact size of B : it needs its definition, not just a declaration, i.e. a promise that B will exist at some point.
The simplest thing to do here would be to reorder things this way:
class B{
public:
B(){
}
};
class A{
B b;
};
Edit : see also this question for the difference between declaration and definition.
Further edit : an alternative would be to change your member data to a pointer or a reference.
Do note that this isn't a trivial syntax change: it has implications on the life-cycle of your objects since the object pointed by A::b may then survive the destruction of A.
If what you want is composition (B is a part of A and dies with A), using a pointer will make your life harder with little benefits.
More edits(!) : just realized I misread the end of your question; what are the reasons preventing you from declaring B before A ?
If they cannot be worked around, you may have to go the pointer route. These reasons might be a sign that your objects are too tightly coupled though ! (perhaps B needs to be an inner class of A ? Or simply be merged into a single object ?)
class A;
class B {
A * getA();
};
class A {
B b;
};
This is the typical way to solve this. You must have B's definition in order to have a B b; member.
You need a forward declaration in order to declare a reference/pointer to B, you need the full definition in order to do anything else with B (such as defining a variable, calling a member function and so on)
You can do what you wish if you change the reference to b into a pointer to B.
class A{
B* bPtr;
};
class B{
public:
B(){
}
};
In principle, you don't need an explicit declaration - that is, a forward declaration is all that is needed - when you don't need the actual size of the class, or access to the types and member functions inside the class.
In your original example, you are making a direct reference to B. As a result, the compiler needs to know everything about B, thus requiring an explicit declaration instead of a forward one.
By having your A class declaration using a pointer to B, then you can get away with a forward declaration.
edit
Some links might explain the concept for you:
http://www.goingware.com/tips/parameters/notrequired.html
http://www-subatech.in2p3.fr/~photons/subatech/soft/carnac/CPP-INC-1.shtml
http://www.codeguru.com/forum/showthread.php?t=358333 (see post #2)
http://en.wikipedia.org/wiki/Forward_declaration
C++ has the concept of an "incomplete" class and it is something you need to know.
Using an incomplete class allows you, in many situations, to use a class just knowing it is one, without knowing what is in it.
This enables the class detail to change later without requiring a recompile, thus it is a far weaker dependency in the coupling model.
You need a complete class to:
Have an instance of one.
Derive from it
Call any method on it.
delete a pointer to it.
You only need an incomplete class to:
Hold a pointer or reference to it.
Pass a pointer or reference to a function that takes a pointer or reference. (This can be a function that deletes the pointer, as long as it is fully defined at that point).
I think you only need an incomplete class to declare a function that returns one, and possibly to declare a function that takes one as a parameter, but at the time you define or call the function it needs to be complete, even if you don't use the return value.