Encapsulating a private enum - c++

Previously I've defined enumerated types that are intended to be private in the header file of the class.
private:
enum foo { a, b, c };
However, I don't want the details of the enum exposed anymore. Is defining the enum in the implementation similar to defining class invariants?
const int ClassA::bar = 3;
enum ClassA::foo { a, b, c };
I'm wondering if this the correct syntax.

C++ doesn't have forward declarations of enums, so you can't separate enum "type" from enum "implementation".
The following will be possible in C++0x:
// foo.h
class foo {
enum bar : int; // must specify base type
bar x; // can use the type itself, members still inaccessible
};
// foo.cpp
enum foo::bar : int { baz }; // specify members

No, enum ClassA::foo { a, b, c }; is not correct syntax.
If you want to move the enum out of the header and into the implementation (.cpp) file, then just do that. If you want to use the enum for parameter types of methods of the class, then you cannot move it, so just leave it private.

Related

Why is a forward declaration in a function declaration allowed?

While reading about the visitor pattern I ran into this snippet of code:
virtual void visit(class Composite *, Component*) = 0;
This is a member function, and it seems to be forward declaring the class Composite inside its parameters. I tried this with just a normal function, like so:
void accept(class A a);
for some class A that I haven't declared or defined yet and the code worked fine. Why is this allowed? How, if at all, is it different from forward declaring before the line? Has anything changed recently in the standard in regards to this?
Many people are claiming this is a leftover of C, but then why does this code compile fine in C++, but not C?
#include <stdio.h>
int process(struct A a);
struct A{
int x;
};
int process(struct A a){
return a.x;
}
int main(void)
{
struct A a = {2};
printf("%d", process(a));
return 0;
}
This is called an incomplete type, and is a concept C++ inherited from C.
Incomplete types work this way: before you've defined a class B in your code, you can use class B varname as, say, an argument in function prototypes, or use pointers to this type as class B* ptr - anywhere where no details about a type besides its name are really needed.
Actually, you can write it differently - just put a class B; (which should work as a class declaration) before you use it as an incomplete type, and then you can write B varname instead of class B varname.
Pointers to incomplete types are often used with opaque pointers, which are probably the most common use of incomplete types in C++. Opaque pointers are described well enough in the linked Wikipedia article. Put short, it is a technique that allows your API to hide an entire class implementation.
Using the incomplete type syntaxis you describe in your question, the example code from Wikipedia:
//header file:
class Handle {
public:
/* ... */
private:
struct CheshireCat; // Not defined here
CheshireCat* smile; // Handle
};
//CPP file:
struct Handle::CheshireCat {
int a;
int b;
};
can be rewritten as:
//header file:
class Handle {
public:
/* ... */
private:
struct CheshireCat* smile; // Handle
};
//CPP file:
struct CheshireCat {
int a;
int b;
};
Note this: these code snippets are not equivalent, as the former defines a type Handle::CheshireCat, while the latter has it simply as CheshireCat.
On the code you gave as an example:
In C, the reason it doesn't compile is quite simple: the struct A in the function prototype is a declaration scoped to the function prototype, and thus it is different from the struct A which is declared latter. C and C++ have slightly different rules for this specific case. If you forward-declare the struct like this: struct A; before the function prototype, it will compile in both languages!
Other notable uses of this syntaxis:
This syntaxis has an important place as part of C++'s backward compatibility with C. You see, in C, after defining or forward-declaring a struct like this: struct A {}; or struct A;, the type's actual name would be struct A. To use the name as A, you needed to use a typedef. C++ does the latter automatically, but allows you to use A both as struct A and A. Same goes for class-es union-s, and enum-s.
Actually, some argue this has a semantical importance. Consider a function with the following signature: int asdf(A *paramname). Do you know what A is just by looking at the declaration? Is it a class, struct, enum or a union? People say that a signature like that can be made clearer in such a way: int asdf(enum A *paramname). This is a nice way of writing self-documenting code.
In C, structure names were not accessible without the struct keyword:
struct Foo {};
void bar(struct Foo foo) {...}
You could get around this by using a typedef as well:
typedef struct Foo {} Foo;
void bar(Foo foo) {...}
In C++, this remains for backward compatibility. It's been logically extended, including support for the class keyword instead of struct. class Composite * is almost equivalent to just saying Composite * in this regard. It is not necessarily used as a forward declaration, just accessing the type name.
Note that it can still be used to disambiguate if necessary:
struct Foo {};
void Foo();
int main() {
Foo foo; //error: Foo refers to the function
struct Foo foo; //okay: struct Foo refers to the class
}
Now the same declaration can introduce a type name, like it does in your accept example and possibly does in the visit example. For a function at namespace scope, if the class being declared is not found, it will be declared in the namespace containing the function (see N4140 [basic.scope.pdecl]/7).
This means that the following will not compile due to the struct/union mismatch:
void foo(struct Bar bar);
union Bar;
The above code is roughly equivalent to:
struct Bar;
void foo(Bar bar);
union Bar;

C++ Forward declaring class scoped enumeration

I'm wondering if it's possible to forward declare an enum that's defined within another class scope. For example, consider the following:
//A.h
class A
{
public:
enum class type: unsigned long { /*some stuff*/ }
};
Now, in another header I'd like to forward declare the 'type' enum (suppose class B below has a function that does something with A::type)
//B.h
enum A::type; //use of undefined type 'A'
class B
{
public:
UseTypeEnum(A::Type&);
};
This doesn't work either:
//B.h
class A;
enum A::type; //still use of undefined type
class B...
There's no problem if the enum is declared at global scope in A.h.
Is there any way to do this?
You can't declare nested types outside the class definition.
If you need to use them outside the class, you will have to either include the class definition, or move them into a namespace.

Accessing enum values from other class

In my project, I have an enum defined in a class, that is used throughout that class. During refactoring, that enum was moved to another class. So I simply typedefed it in my original class, like this:
class A {
public:
enum E {e1, e2};
};
class B {
public:
typedef A::E E;
};
Now variable definitions, return values, function params, etc. work perfectly. Only when I want to access the values of the enum inside my second class, I still have to qualify them with the surroundig class's name,
e.g. E e = A::e1;
Is there a way to avoid this, or do I have to copy that into every occurance of the enum values?
You put each enumeration into a nested class that you can typedef within your own class:
class A {
public:
struct E { enum EnumType { e1, e2 } };
};
class B {
public:
typedef A::E E;
};
Then it's just E::EnumType instead of E but you get full auto-importation.
If you're not above using c++11, you could have a look at enum classes.

Inheriting from a template class, using a type defined in the derived class

I'm trying to inherit from a template class, using a type defined in the derived class.
I have tried this, but it doesn't work.
class A : std::vector<A::B>
{
enum B { foo, bar };
};
Is there an elegant way of doing this ?
Edit : I know that it works if B is defined earlier. But i'm looking for a solution that allows encapsulating the type B inside the A class.
You can't forward declare an enum in C++03. Just use normal composition by having a the vector as a member and forwarding by hand.
You will have to define enum B before it's use to inherit.
Also, you're not inheriting from the Standard vector, are you?
In my view, the best (admittedly indirect) solution is to use composition rather than inheritance:
class A
{
enum B { foo, bar };
std::vector<B> bs;
};
If for some reason you need (or really want) to use private inheritance to embed the vector in your object, then the type will need to be defined before the class, at namespace scope, since types cannot be used before they are declared. If they are not indended to be accessed by users of the class, and you don't want to pollute the namespace containing your class, then you could put them inside a namespace to indicate that they are implementation details:
namespace details
{
enum B { foo, bar };
}
class A : std::vector<details::B>
{
typedef details::B B; // if you don't want to write "details::B" everywhere
static const B foo = details::foo; // if you don't want to write "details::foo" everywhere
// and so on.
};
Thanks everyone for your answers, but I just found a (edit: bad) solution :
namespace
{
enum B_type { foo, bar };
}
class A : std::vector<B_type>
{
typedef value_type B;
};

Class prototyping

I have put several instances of class b in class a but this causes an error as class a does not know what class b is.
Now I know I can solve this problem by writing my file b a c but this messes up the reachability as well as annoys me. I know I can prototype my functions so I do not have this problem but have been able to find no material on how to prototype a class.
does anyone have an example of class prototyping in c++.
as there seems to be some confusion let me show you what i want
class A
{
public:
B foo[5];
};
class B
{
public:
int foo;
char bar;
}
but this does not work as A cannot see B so i need to put something before them both, if it was a function i would put A(); then implement it later. how can i do this with a class.
You can declare all your classes and then define them in any order, like so:
// Declare my classes
class A;
class B;
class C;
// Define my classes (any order will do)
class A { ... };
class B { ... };
class C { ... };
You're looking for declarations.
class A;
class B {
A MakeA();
void ProcessA(A a);
};
class A {
B bs[1000];
};
If you forward declare a class, you can
declare functions taking and returning it or complex types made of it
declare member variables of pointer or reference to it
This basically means that in any case which doesn't end up with instances of A inside B and vice versa, you should be able to declare and define any interface between A and B.
The usual way to resolve circular dependencies is to use a forward declaration:
// Bar.h
class Foo; // declares the class Foo without defining it
class Bar {
Foo & foo; // can only be used for reference or pointer
};
// Foo.h
#include <Bar.h>
class Foo {
Bar bar; // has full declaration, can create instance
}
You can provide a full declaration and definition in another file. Using the forward declaration, you can create pointers and references to the class, but you cannot create instances of it, as this requires the full declaration.
class b;
class a {
public:
b * inst1;
};
class b{
....
};
Is this what you needed ?