I have a class hierarchy and i am writing a virtual function in it. Say there are three classes
class A { virtual A* test(); }; ( File A.h )
class B : public A { virtual C* test(); }; ( File B.h )
class C : public A {}; ( File C.h )
Now is it possible for me to avoid including C.h in B.h, by doing some kind of forward declaration saying that C is a sub-class of A?
Thanks,
Gokul.
You can tell the compiler only three things, in three different ways, about a class C:
That it exists. You do that by forward-declaring the class.
How it is structured. You do that by declaring the class.
How it behaves. You do that by defining the class' member-functions.
If you want to tell the compiler what the class derives from then you're talking about how the class is structured. You must then show the compiler the class' declaration, there's no other way.
C/C++ distinguish between complete types and incomplete types. If you forward-declare class C like this:
class C;
It will be available as an incomplete type, which means you can declare a pointer to it. However, you can't subclass it until C is fully declared, as C is an incomplete type at this point.
You can use class C inline where you would just use C. What you want is:
class B : public A { virtual class C* test(); };
There's no reason to specify B::test() as returning a C* because a C* will always downcast to an A* and any client making correct use of the interface to A will expect an A*. If clients of B expect only C* they should either call a different function or take responsibility for ensuring the returned A* upcasts to a C* using dynamic_cast.
It's also perfectly fine to forward-declare class C before class A and have A::test() return a C* - subclassing doesn't make any difference when declaring pointers to incomplete types in this case.
Related
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;
}
I have a C++ lib that makes use of a object hierarchy like this:
class A { ... }
class B : public A { ... }
class C : public A { ... }
I expose functionality through a C API via typedefs and functions, like this:
#ifdef __cplusplus
typedef A* APtr;
#else
typedef struct A* APtr;
#endif
extern "C" void some_function(APtr obj);
However, say a use of the C API does something like this:
BPtr b = bptr_create();
some_function((APtr) b);
This is polymorphically valid, since B extends A, and my API depends on such functionality being possible, but I want to make sure that this will still interoperate properly with the C++ code, even if B overrides some of A's virtual methods.
More importantly, why or why not? How can C++ identify at runtime that the obj parameter of some_function is actually a pointer to B, and therefore call its overridden virtual methods instead?
The C code is not valid (nor would the equivalent C++ code in a context where the class definition is not visible) because what C does in this case is the equivalent of a reinterpret_cast. Note that in a simple situation like yours it will likely "work" because most compilers will put the single base object at the beginning of the derived object, so a pointer adjustment is not necessary. However, in the general case (especially when using multiple inheritance), the pointer will have to be adjusted to point to the correct subobject, and since C does not know how to do that, the cast is wrong.
So what is meant with "pointer adjustment"? Consider the following situation:
class A { virtual ~A(); int i; ... };
class B { virtual ~B(); int j; ... };
class C: public A, public B { ... };
Now the layout of C may be as follows:
+----------------------------+----------------------------+
| A subobject (containing i) | B subobject (containing j) |
+----------------------------+----------------------------+
where the virtual pointers of both the A and B subobjects point to C.
Now imagine you've got a C* which you want to convert to a B*. Of course the code which receives the B* may not know about the existence of C; indeed, it may have been compiled before C was even written. Therefore the B* must point to the B subobject of the C object. In other words, on conversion from C* to B*, the size of the A subobject has to be added to the address stored into the pointer. If you do not do this, the B* will actually point to the A subobject, which clearly is wrong.
Now without access to the class definition of C, there's of course no way to know that there even is an A subobject, not to mention how large it is. Therefore it is impossible to do a correct conversion from C* to B* if the class definition of C is not available.
C++ uses the virtual function table which is in memory per class ,
and when an object is created of that particular derived class its
virtual table decides which function gets called.
So its bit c++ compile time Plus Runtime magic :)
http://en.wikipedia.org/wiki/Virtual_method_table
Short answer: Yes this will work.
Why: since A and some_function is implemented in C++, all virtual function calls will occur in C++ code as usual, where the class definition is included, and there is nothing magic about it. In C code only opaque pointers are passed around, and C code never will be able to call the virtual functions directly, because it never could compile the definition of A.
I have a c++ where in classes A and B each one has a member of the other class. How can I solve this ?
class A {
B memberY;
}
class B {
A memberX;
}
You use pointers and forward declarations.
//A.h
class B; //forward declaration to class B
class A {
B* memeberY;
}
header for class B:
//B.h
class A; //forward declaration to class B
class B {
A* memeberX;
}
You can't do this with object instances, only with pointers, since an instance would require the compiler to know the full definition of the class.
Note that if memory management is assigned to the class, you should free the memory on the destructor. That means you should also override the copy constructor and operator = in your classes.
You can have one of the classes contain an object of the other class, but you have to include the other classes' header in the header. The other one would have to be solved with a forward declaration.
It isn't possible as you would like it. One of those classes has to be a pointer to the other one. You cannot have a recursive relationship of actual objects -- the size of the object would be infinite.
So you probably need something like this:
struct B;
struct A
{
B * myB;
};
struct B
{
A * myA;
};
Now, construction becomes a problem since they both need a reference to each other. That is why I can't provide you with a constructor, since I don't know how you will construct these objects.
You now also have a cleanup problem, since presumably one of these objects owns the other -- they both can't own each other. That excludes the use of unique_ptr. I would have used smart_ptr, but then you still have a memory link unless you have some function to break the circular reference.
But if you'd better indicate why you want to do this perhaps a more appropriate answer can be given.
I have a class manipulating only shared_ptr to an inheritance hierarchy (quite simple, there are a few classes, say A, B, C etc. inheriting from a single class Base). Since I do not need to manipulate the instances of A, B, C... themselves, they are only forward declared. However, the compiler chokes when I try to pass a shared_ptr<A> to a method taking a shared_ptr<Base>, since the compiler does not know that A inherits from Base. Is there any other way than either static_pointer_castor #includethe header of class A? And if not, which one would you choose?
EDIT: adding some code
// in some file: (Base.h)
class Base
{
/*code*/
}
// in another file (A.h)
class A : public Base
{
}
// in my file (impl.cpp)
class A; // forward declaration
void Dummy()
{
std::shared_ptr<A> myPtr;
// we have somewhere: void sillyFunction(shared_ptr<Base> foo)
sillyFunction(myPtr); // does not compile, as no conversion is found.
}
Is there any other way than either static_pointer_castor #includethe header of class A?
No. In fact, the #include is the only way to do it properly (static_pointer_cast either wouldn't work or invokes undefined behavior). You can't cast ordinary pointers between incomplete subclass and superclass, either.
This may seem weird but I have a problem in one of my programs where I have a class A which needs a variable of class B inside it, and the class B needs a pointer to class A inside it, so that I can determine which class is attached to what....
I get errors because in class A it says that the class B is not defined yet, and in class B it says class A isn't defined yet...
Both of my header files which contain the separate classes include each other and I have tried to forward declare my classes e.g. class A; class B; but I get compiler errors such as:
error C2079: 'CFrame::menu' uses undefined class 'CMenu'
I need a pointer to class A in class B because I want to pass it to another class later on.
You need to declare A before you define B:
class A; // declaration of A
class B // definition of B
{
A* foo;
// ...
};
class A // definition of A
{
B bar;
// ...
};
This kind of declaration is often referred to as a forward declaration.
First of all, consider redesigning your classes. Circular dependencies are bad practice, and chances are that you could avoid this altogether with a more elegant class design.
That said, you can get around the problem using forward references (at which point, you need to use pointers or references) -
class B;
class A
{
B *pPtr;
};
class B
{
A typeA;
};
You may be able to avoid forward declaration by simply specifying what a "B" is:
class A
{
public:
class B* pB;
};
class B
{
public:
A a;
};
If you're having problems with this, it may be because you're including implementation along with your declarations. If you separate the implementation and the header, you might have fewer problems in this scenario.