It is well-known that one cannot have a member of the type you're defining:
class Foo {
Foo member;
};
The reason is that this is an infinitely recursive, infinitely large object. However, we can have static members:
class Foo {
static Foo member;
};
We can do this because Foo is acting like a namespace; instances of Foo do not contain .member, so there's no infinite reference. Put another way, .member belongs to the class, not to the instance. What I would like to do is very similar:
class Foo {
class Bar {
Foo member;
};
};
Once again, Foo is acting like a namespace. Instances of Foo are actually empty. I would have to make a non-static field Bar Foo::bar; to start getting layout issues. Unfortunately, my compilers disagree (e.g. GCC):
<source>:3:14: error: field 'member' has incomplete type 'Foo'
Foo member;
^~~~~~
For what technical reason is this not allowed?
Long story short, it was easier to disallow this than to allow.
Here is an example that shows what could be difficult about it: C++ lets you combine nested class definition with a member declaration, like this:
class Foo {
class Bar {
Foo member;
} bar; // <<== Here
};
It is clear why this definition must be disallowed: unlike a class definition which could have been OK, member definition makes size computation impossible.
Of course the writers of the standard could have allowed class definitions to pass, at the expense of giving compiler writers additional work. However, it looks like they decided that allowing this feature is not worth the trouble, so they didn't make it an exception from the requirement of the class to be complete at the point of declaring an instance.
There is nothing wrong with what you what to do, and you can do so with different syntax.
Since the compiler wants to determine the size of class Bar, it needs to know the size of class Foo, But Foo's definition is not yet complete (The source code has not been entirely parsed by the compiler). The definition of Foo must be completed before using it in Bar.
Instead try forward declaring Bar inside Foo, then completing the definition of Bar after Foo, This way the size of Foo can be determined for use in Bar.
class Foo {
class Bar;
};
class Foo::Bar {
Foo member;
};
It's not allowed because you can't define a class with a member with an incomplete type, period. At the end of the class definition the class becomes complete and that is only possible if the sizes of all of its members are known.
For example, you get the same error, for the same reason, without nesting classes like this:
class Foo;
class Bar {
Foo member;
};
Sure, in your example the language could defer completing the definition of Foo::Bar until Foo is defined, but this would be inconsistent with how classes are defined generally. You'd have the weird behaviour of Foo::Bar being incomplete at a point in the source code after it was fully defined.
Related
I have the following scheme:
struct Baz {};
struct Qux {};
struct Base {
virtual ~Base() {}
virtual void foo() = 0;
};
template<typename T> struct Identity { static bool const value = false; };
template<typename T> void bar(T) { static_assert(Identity<T>::value, "Busted!!!"); }
template<> void bar<Baz>(Baz) {}
template<typename T>
struct Derived : Base {
T m;
void foo() { bar(m); }
};
int main() {
Base *b0 = new Derived<Baz>;
b0->foo();
Base *b1 = new Derived<Qux>;
(void) b1;
}
That is, I have a pure virtual class Base and a template class Derived that inherits from Base and overrides the pure virtual function foo as required. Now, inside foo I call function template bar. bar has a specialization for class Baz but not for class Qux. When in main I'm trying to materialize an object of Derived<Baz> everything's OK. But when I try to materialize an object of Derived<Qux> compiler hits static_assert.
Q:
Is there a way to transform my code in such a way that compiler will hit static assert in Derived<Qux> only if Derived<Qux>::foo() is called.
That is, materializing an object of Derived<Qux> will pass:
Base *b1 = new Derived<Qux>;
But when later in code the programmer tries to call:
b1->foo(); // compile error static assert
The standard says an interesting thing at [temp.inst]/9:
An implementation shall not implicitly instantiate a function
template, a variable template, a member template, a non-virtual member
function, a member class, a static data member of a class template, or
a substatement of a constexpr if statement, unless such instantiation
is required. It is unspecified whether or not an implementation
implicitly instantiates a virtual member function of a class template
if the virtual member function would not otherwise be instantiated.
The decision of instantiating a virtual function is up to the implementation, but only if it is not needed otherwise. The question we are faced with is therefore: when is the definition needed according to the standard itself?
The answer is at [class.virtual]/11 and [temp.inst]/2:
A virtual function declared in a class shall be defined, or declared pure in that class, or both; no diagnostic is required
The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or noexcept-specifiers of the class member functions
So any instantiation of the class template, will instantiate a declaration of Derived::foo, which by a chain reaction requires a definition. So the definition must be instantiated too, if it is available.
The only way an implementation can exercise the leeway it is given in the first quoted paragraph, is if Derived::foo is pure virtual too. As an example, both Clang and GCC do just that. That of course is likely to be of limited help to you.
So to make a long story short, it's a no-starter, so long as the function is virtual (and not pure virtual).
#StoryTeller gives a detailed answer referencing the spec, etc. but I'm going to push back on your question and ask what you are really trying to do. As the question is written, it is dead obvious the answer is "no" because you are asking for a compile time error on something that is only determinable at runtime. E.g.:
Base *b;
if (user_input() == 42) {
b = new Derived<Baz>();
} else {
b = new Derived<Qux>();
}
b->foo();
Do you want a compiler error for this case? If so you'll need to define the conditions under which you think Qux::foo should be considered to be "called." At present the compiler is assuming a method defined as virtual in an instantiated class is called. Clearly you want something less conservative, but what?
If you have more specific compile time type information, it may be possible to catch the error at runtime. E.g.
Derived<Qux> d = new Derived<Qux>();
d->foo();
If foo is a non-virtual templated method, it is possible it could validate the base type at compile time and then dispatch to the virtual method. (It will likely require changing the signature of foo to have the type somehow.)
A far better solution would be to break different types of functionality in the interface into different classes and introduce a mechanism to get specific interfaces on a given concrete class. This can be checked at compile time if you have the concretely types class in hand and at runtime if doing a dynamic lookup of an interface.
Am I missing something here?
class Foo;
class Bar {
public:
Foo foo;
};
class Foo { };
Error:
error C2079: 'Bar::foo' uses undefined class 'Foo'
When you forward-declare a class, you can make pointers and references to it, but you cannot make members of the type of forward-declared class: the full definition of Foo is needed to decide the layout of the outer class (i.e. Bar), otherwise the compiler cannot make a decision on the size and the structure of Bar.
This is allowed, though:
class Foo;
class Bar {
public:
Foo* fooPtr;
Foo& fooRef;
};
The reason the pointers and references to forward-declared classes are allowed is that the sizes of pointers and references do not depend on the structure of the class to which they point (or which they reference).
Yes you are missing something important: A question.
I assume you want to know what's wrong in the code, and why the compiler issues an error.
The compiler has to know the size of Foo in order to calculate the layout of the class Bar. The size of Foo objects is determined by their layout, to know that layout, the compiler has to know the class definition. At the point where you declare the Member variable foo, it merely knows that Foo exists, but not its size, because you have given it only a declaration, not a definition before.
Is there a way to explicitly declare a base class as abstract in C++?
I know that I can create a pure virtual function in the class which will implicitly declare a class as abstract. However, I don't want to have to create a dummy function just to define in in derived classes.
I could also make the constructor protected, which would prevent the instantiation of the object, but that doesn't actually mark the class as abstract.
So, is there a way to do this? (I am using C++11, if that added a way to do this, but I didn't find anything that looked right)
You can make the destructor pure-virtual. Since you always need a destructor, there's no additional mental cost:
struct Foo
{
virtual ~Foo() = 0;
};
inline Foo::~Foo() { }
(You do of course need an implementation of the destructor, so you have to provide one out-of-line.)
You can still make the destructor protected, which is good practice following the "make non-leaf classes abstract" rule.
Example:
struct Bar : Foo { };
// Foo f; // Error, Foo is abstract
Bar b; // OK
I like Kerrek's answer. That way the class cannot be instantiated and therefore is abstract.
However, it still isn't obviously clear that the class is abstract unless you scan through the entire declaration of the class and see that the destructor is virtual.
Another idea I had is you could create a pre-processor definition for the word "abstract" using #define. This way you could do something like the following:
abstract struct Foo {};
which would be no different than
struct Foo {};
The problem I see with this is that this doesn't force the class to be abstract, so you could use a macro to also declare the virtual destructor. Something like:
#define ABSTRACT_CLASS(class_name) \
class class_name { \
virtual ~class_name() = 0; //
And then use it like so:
ABSTRACT_CLASS(Foo) {
// class declaration
};
Which would be turned into:
class foo {
virtual ~class_name() = 0; // {
// class declaration
};
Disclaimer: My macro might be slightly off. I'm not sure if it'll actually paste class_name with the ~ and the () touching the variable name. Also, I'm not sure if I'd do this myself, it's not the most beautiful solution, especially commenting out the brace since that wouldn't work if you put it on the next line. But you asked how you could mark something as abstract and I gave it to you!
Is there a way to explicitly declare a base class as abstract in C++?
No, there is not. A class is abstract only if it has at least one abstract method declared in it. If you do not want your base class to be instantiated directly, then a protected constructor is a good choice.
Using static class members in a class is a common practice. consider the following definition:
foo.h
class foo
{
public:
virtual ~foo();
protected:
foo();
static foo ms_oFooStaticObject;
}
foo.cpp
foo foo::ms_oFooStaticObject;
foo::foo(){}
foo::~foo(){}
void main()
{
int i;
}
while compiling the above code there is no compiler error, and you can simply run in step mode and observe the static c-tor being executed.
how can this be? is this a compiler bug?
I am using visual studio 2005 (Professional Edition) with SP1 (SP.050727-7600)
It's not a compiler bug - constructing static instances of the class being defined does not trigger recursive construction (as a non-static member of type foo would do), so it is perfectly fine.
At the point of ms_oFooStaticObject's definition (in foo.cpp), foo is a complete type and its constructor, though protected, is accessible to ms_oFooStaticObject.
#user797308: I assume you would have no problem if someone declared and defined a global variable named ms_oFooStaticObject. In other words, rather than defining foo foo::ms_oFooStaticObject; define foo ms_oFooStaticObject; (This would require the constructor was public, of course).
Plain old vanilla global variables are declared via extern <type> <global_name>; and defined using <type> <global_name>; (possibly with some initial value).
Those static members in a class are really just global variables with the class name prepended in front of their names. The class definition is declaring them. Think of the declaration of ms_oFooStaticObject inside of class foo as being analogous to extern foo ms_oFooStaticObject;. How about the definition of the variable? That's what that foo foo::ms_oFooStaticObject; statement is doing.
The comparison with globals is quite apt. There's a lot of baggage associated with globals. It is a good idea to think of the static members of a class as having the same kinds of problems as do globals in general.
Edit
Nawaz's response triggered a thought. user797308's problem might be that foo::ms_oFooStaticObject itself is protected, so how can it be defined at file scope? The answer is that because the language requires those static data members to be defined at file scope, the language of course has to allow such definitions, even for static members that have non-public visibility.
Constructor foo::foo() is executed because of static variable definition you did in foo.cpp file:
foo foo::ms_oFooStaticObject;
You are invoking the object of class foo.
Let me guess. I think you're wondering because the foo is made protected, and therefore, you think the following line must give error, as it tries to invoke the non-public constructor from outside.
foo foo::ms_oFooStaticObject; //definition lies outside the class
Well, that is not true. ms_oFooStaticObject is NOT a global object, though at first it seems it is, seeing its definition which is outside the class.
The fact is that ms_oFooStaticObject is still a member of the class, even though its definition is outside the class. And like any member, it can access not only protected members, it can access even private ones:
class A
{
A() { cout << "constructed" << endl; } //private constructor
static A a;
};
A A::a; //okay - member has access to private constructor!
A b; //error - non-member doesn't has access to private constructtor
Compile and see the error message along with line number: http://www.ideone.com/qocH0
By the way, your main() is non-standard, it should be one of these:
int main();
int main(int argc, char *argv[]);
I have a class that I made that I am using in thread above the class. Even though I did a prototype of the class at the top it still throws off those errors
error C2027: use of undefined type 'foo'
class foo;
DWORD WINAPI demo(LPVOID param)
{
foo a;
}
class foo
{
public:
int x;
};
Even though I did a prototype of the
class
With a forward declaration of the class you can create pointers and references to the class. This is because pointers/references are represented the same across all classes/structs/etc. They're all just addresses of memory. So, for example, you could create a second class that can accept or contains pointers or references before fully defining the class, ie:
class Bar
{
private:
foo* aFoo;
public:
Bar(foo* foo2) : aFoo(foo2) {}
};
However, until the compiler sees the full definition of the class, you can't instantiate it. Otherwise the compiler doesn't know how much memory to allocate and how to call the constructor and other methods. In most cases, C++ expects things to be defined before they are used. Forward declaration lets you get around this a little bit because pointers and references for any class are identical. So you can promise to the compiler you'll fully define it later.