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.
Related
I am a beginner in C++, I had a question regarding nested class in C++, how do you access the protected or private member of an enclosed class?
class A{
class B{
protected:
B(){};
};
B var; <=== error as the constructor B is protected
};
One solution is making constructor of B public, but this exposes it'a scope and other function can instantiate it, which I don't want. What's a way to do deal with this ?
You can use friend class:
class A
{
class B
{
friend class A; //<-- makes A a friend of B
protected:
B(){};
};
B var; //<-- OK
};
I believe the question that was asked does not get at the real issue. It is almost an XY problem, but fortunately it has sufficient hints for the real issue to be deduced. Still, in the interest of propriety, I will address the question that was asked before addressing what I believe is the real issue.
how do you access the protected or private member of an enclosed class?
The same way you grant such access when the classes are not nested: the class with the protected or private member declares the other class (or function) as a friend. Just be aware that this is a bit of a sledgehammer approach, so it is advisable to consider alternatives first.
One solution is making constructor of B public, but this exposes it's scope and other function can instantiate it, which I don't want.
No, it doesn't expose anything outside A. You have declared B as a private type within A, which means only A can reference B. With your current setup, there is no functional difference between making A a friend of B and making all members of B public. In either case, A has full access to B and nothing outside A knows that B exists.
While I suspect that B is supposed to be public, the OP has had days to correct this detail. In addition, the OP posted a new question after this possible oversight was pointed out, so I must conclude that the OP does not regard it as an oversight.
Now we get to what I believe is the real issue: how to construct a public nested class from the outer class without allowing public construction.
What's a way to do deal with this ?
If there is a possibility that B might become a public type at some point (a reasonable thing to guard against), you should consider alternatives to friendship. One alternative is to put the constructor of B under lock-and-key. This could be extended to other private members of B, but that is perhaps not necessary.
One advantage of this approach is that access is granted to only the constructor, not to all private members. This helps preserve encapsulation. Furthermore, this approach allows construction to be handed off to helper functions, such as those from the standard library. For example, an emplace_back method for a standard container could construct a B object as long as the method was given a key. This might be more convenient than relying on friendship, depending on how B objects are to be used.
The key
The "key" is a private class of A. It is likely going to be an empty class, as it does not need functionality. All the key needs to do is exist and be inaccessible outside A.
class A{
private:
class KeyForB {};
// Rest of the definition of A
};
The lock
The "lock" is a constructor that accepts the "key" as a parameter. This parameter will not be used by the constructor; all it does is signify that the caller is allowed to call the constructor.
class B{
public:
/* explicit */ B(KeyForB /* unnamed */) : B() {}
protected:
B() {}
};
There are a few details worth looking at. First, you might have noticed that B just used a private member of A! How? There is a special rule that says that nested classes are considered part of the outer class, and as such they can access the private (and protected) members of the outer class – no friend declaration necessary.
Second, the lock delegates to the protected constructor. This may seem odd, but it does serve a purpose. Not only does it keep the default constructor available to B, but also it allows the compiler to optimize away the lock and key. Consider what would happen if the constructor was so large that the compiler opted to not inline it. If a function is not inlined, then parameters cannot be optimized away. In this case, that would mean that a KeyForB would need to be constructed and placed on the call stack. In contrast, the lock is so simple that it should be inlined under any level of optimization. It gets inlined to a call to B() and the unused KeyForB is eliminated from the executable.
Third, there is a comment acknowledging that some coding guidelines recommend marking as explicit most constructors that take a single parameter. This is sound advice. However, in this case, the only reason to create a KeyForB object is to construct a B object. So in this case, it might be acceptable and convenient to leave this conversion implicit.
Putting it together
The only remaining piece is to write a constructor for A, as the compiler-provided default constructor is deleted because it would be ill-formed.
class A{
private:
class KeyForB {};
//public: // <-- possible future change
class B{
public:
B(KeyForB) : B() {}
protected:
B() {}
};
public:
// Default constructor
A() : var(KeyForB{}) {}
private:
B var;
};
It might be worth noting that if the type of var were to change from B to std::shared_ptr<B>, this approach would not run into "make_shared for friend class throwing error", as giving a key to make_shared would enable construction.
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 accidentally shadowed some member variables of a (base) struct with private members in a class derived by the base struct.
struct Base {
int a;
}
class Derived : public Base {
private:
int a;
...
That was a mistake in my case, causing a sneaky bug (luckily caught while testing).
As I think that shadowing members on purpose is really rare (if not considered bad practice at all), I wonder why the compiler is not raising at least a warning (ok, not an error because shadowing is legally permitted)?
The compiler I used is Microsoft Visual C++ 2015, warning level 4).
I wonder if other compilers (i.e. GCC) provide a specific warning for this situation?
Whether shadowing is bad or good depends on the order in which you introduced the conflicting names.
Suppose you have a class library, and one of the classes is this:
struct Base {
int a;
};
Later, customer A who is using your class library writes this:
class DerivedA : public Base {
private:
int a;
};
In this case, shadowing is probably unintended. The customer has accidentally shadowed Base::a.
However, suppose you also have customer B, who writes this:
class DerivedB : public Base {
private:
int b;
};
So far so good. Now you build up your library so it uses Base objects, and customer B who uses your library builds up a body of code that uses both Base and DerivedB objects.
A few weeks later, you realize that in order to get a new feature, you need to add a new member to Base.
struct Base {
int a;
int b; // new member variable
};
Does this create a problem with your library? Does it create a problem with customer B?
No, it doesn't create any problems.
All of your code that uses Base will continue to use Base, and it can use the b member to get the fancy new b feature. Even if the DerivedB object is passed to a function that expects a Base, the fact that Derived is shadowing b has no effect on Base. Your function that uses Base can say b and it will access the Base member variable.
Meanwhile, all of customer B's code that uses DerivedB will continue to use DerivedB, and when that code says b, it gets DerivedB::b, just like it did before. Phew, shadowing saved the day!
(Of course, if customer B wants to start taking advantage of the new b feature, then customer B has to do extra work to resolve the conflict. But the important thing is that the shadowing didn't create any new problems in existing code.)
At the end of the day, whether shadowing is good or bad depends on the order in which you introduced the conflicting names. This is not something a compiler has insight into.
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.