How to prototyply declare an inherited class in C++? - 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)

Related

C++ Syntactical anomaly for instantiation of a derived class

I am working with a GitHub library and ran across a derived class instantiation that perplexes me. In abbreviated form,
class A
{
public:
A() {}
int AFunc(void) { return(1); }
};
class B : public A
{
public:
B(void) : A() {}
int BFunc(void) { return(2); }
};
Within an include file, the class is instantiated as follows:
A &tObject = *(new B());
Sample code then refers to 'tObject' as global variable calling methods from class A and/or B.
For example:
tObject.AFunc();
tObject.BFunc();
So here's the question, is that instantiation legal?
The compiler is only fussing on the call to a service class's method, saying that class A has no such member. That error makes sense to me and I've narrowed the issue to the above explanation.
While I do not have broad compiler experience, I have been programming in C++ for many years. I've never seen such a construct.
Would someone kindly explain how an object declared, in my example, as 'class A' can access methods from the derived class B?
In my experience, I've always declared the derived class as a pointer and then accessed methods from the base or derived class using the '->' construct. Oftentimes, I've stored the derived class as a pointer to the base and then performed a cast to convert when or if I needed access to the derived class's methods.
An insight is highly appreciated.
It cannot. The compiler is right to complain, there is no way this is valid. Remember that C++ is a static language, which means that the compiler will try to find a function named BFunc in A, which it cannot, as there is no such function.
This might be a compiler extension of some sort, but anyways, this isn't legal standard C++. Most probably, the author wanted to make BFunc a virtual method in A, which would have made the access legal.
Would someone kindly explain how an object declared, in my example, as 'class A' can access methods from the derived class B?
As explained, this cannot be.
I've always declared the derived class as a pointer and then accessed methods from the base or derived class using the '->' construct.
You can also do this with references, not just with pointers. Although this is done less often than pointers, so this might explain why you haven't encountered this yet.
Oftentimes, I've stored the derived class as a pointer to the base and then performed a cast to convert when or if I needed access to the derived class's methods.
Exactly, this is the correct way to access the derived class members. As then the compiler will know the type of the object and can actually find BFunc and call it. Now, if the type is not really a B, then you have undefined behavior, but yes, this is what one should do.
Also, please get your terminology right:
the class is instantiated as follows
If there are no templates involved, then there is no instantiation happening. The only thing you are doing here is declaring or more specifically defining a variable named tObject.
// The declaration of the reference as a reference to the base class is not a problem, and is actually performed in some STL implementations.
class A
{
};
class B : public A
{
public:
void f1() {}
};
int main()
{
A * a = new B; // You know its OK using pointers
A & a2 = *(new B); // Also OK, a2 is a reference for a place in memory which is-a-kind-of A
// a2.f1(); // Will not compile - compiler only knows for sure its of type A
((B&) a2).f1(); // This will work. There is really a B there
return 0;
}

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

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.

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.

Is a class with empty body an incomplete type?

a class declaration makes the class an incomplete type, so no object of the class could be defined. And the definition of an incomplete type is that its member are not specified. Doesn't that means a class with empty body with no member specified in its definition makes it an incomplete type?
class Empty { };
Empty e1; // okay, but why?
Is a class with empty body an incomplete type?
No, a class with an empty body is simply an empty class, but still a fully defined one. An incomplete type is a type whose full definition is not visible.
class Empty;
// Here, Empty is an incomplete type
class Empty { };
// Here, Empty is a complete type
Per paragraph 3.9/5 of the C++11 Standard:
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. Incompletely-defined object types and the void types are incomplete
types (3.9.1). Objects shall not be defined to have an incomplete type.
Also, per paragraph 9.2/2:
A class is considered a completely-defined object type (3.9) (or complete type) at the closing } of the class-specifier. [...]
As others have said, it is not an incomplete type. In C++ there are times when this kind of thing is desirable.
Consider the following:
template<class T>
class Field
{
public:
virtual std::string toString() const = 0;
};
How can I store this in a collection? Answer is, I can't. But I could do:
class FieldBase
{
public:
virtual ~FieldBase() = 0 { }; // virtual destructor needed, but no other members
virtual std::string toString() const = 0;
};
Now, technically, that doesn't have any members defined, as per your question. It's abstract. It cannot be instantiated. But now we can do:
template<class T>
class Field : public FieldBase
{
virtual std::string toString() const { /* ... */ };
};
I know this slightly deviates from your original question, but it does illustrate that a base-class has nothing defined (except intent), and we can now store these template-classes in a std::vector<FieldBase*> collection.
Yes, it is a complete type. When I last checked the size is one byte (at least on MS's compiler).
In order to create an incomplete struct omit your braces:
struct Empty;
This is also known as a forward declared structure, and is not a definition of the struct.

C++ Using a Class Within a Class

I have a basic question that has bothered me for sometime.
When using a Class within a Class I can define the header of the Class I want to use in the header file. I have seen two ways of doing this and would like to know the difference between the two methods?
ex1
#include "ClassA.h"
class ClassB {
public:
ClassB();
~ClassB();
ClassA* a;
};
#endif
ex2 Here is the other way of doing it. The ClassA Header would be defined in ClassB source file.
class ClassA;
class ClassB {
public:
ClassB();
~ClassB();
ClassA* a;
};
#endif
What are the differences with these two methods?
The comlpete layout of the classA is known to the compiler when you include the class definition.
The second syntax is called Forward declaration and now classA is an Incomplete type for the compiler.
For an Incomplete type,
You can:
Declare a member to be a pointer or a reference to the incomplete type.
Declare functions or methods which accepts/return incomplete types.
Define functions or methods which accepts/return pointers/references to the incomplete type (but without using its members)
But You cannot:
Use it as a base class.
Use it to declare a member.
Define functions or methods using this type.
Use its methods or fields, in fact trying to dereference a variable with incomplete type.
So Forward Declaring the class might work faster, because the complier does not have to include the entire code in that header file but it restricts how you can use the type, since it becomes an Incomplete type.
The second method only allows you to create pointers to ClassA, as it's size is unknown. It may however compile faster as the header for the full definition for ClassA is not included.
The latter is a forward declaration. This way you can declare a pointer or reference to a class, even though you have not yet fully declared it. This can be used to resolve cyclic dependencies. What if, in your first example, A also wants to use a pointer to B. This wouldn't work, because when A is declared, B is not known yet. To solve this, you can use a forward declaration to tell the compiler that there is a class B, and you will tell it later what it looks like.