I want to implement the Visitor pattern in C++ like this:
class Visitor{
public:
virtual ~Visitor();
virtual void visit(C & t)=0;
};
class V : public Visitor{
public:
void visit(C &c);
};
class C{
public:
void accept(Visitor &v){ v.visit(*this); }
};
But the compiler complains abount 2 syntax errors:
Unknown identifier C and Visitor.
Where is the problem?
At the moment the compiler sees
virtual void visit(C & t)=0;
name C is unknown.
You need to forward-declare class C before Visitor
class C;
class Visitor{
...
}
In the C++ language the compiler will not look ahead for names that are yet to be defined or, to say it better, sometimes it does and sometimes it doesn't.
You can say for example
struct Foo
{
Foo(int x) : m_x(x) { }
int m_x;
};
and the compiler will not complain even if you used m_x before defining what m_x is, but however at the module level this look ahead is not present:
struct Foo
{
Bar *p; // Error, Compiler doesn't know what Bar is
};
// Too late, the compiler is not going to read down here while
// analyzing Foo.
struct Bar
{
int x;
};
How do you solve cases in which you need to use something before defining it? By using a special "forward declaration", in which you only state that there will be something with that name and you define later what it is in the specific... for example
struct Foo; // There will be a struct Foo defined somewhere
struct Bar
{
Foo *p; // Fine, even if the compiler doesn't really know Foo
};
struct Foo
{
Bar *q; // Fine and no forward needed... Bar is known at this point
};
More or less the rule is: in a single class all methods can see all other methods and all members even if they are defined later in the class, at a module level instead every name must be known before it can be used.
Sometimes a more complex pattern is needed, like
struct Foo;
struct Bar
{
void doit(Bar x);
};
struct Foo
{
void doit_too(Foo x);
};
void Foo::doit(Bar x) { ... }
void Bar::doit_too(Foo x) { ... }
In the last case you are forced to put the implementation of both methods after the declarations of both classes because just knowing that Foo is a class is not enough to be able to compile a copy operation (note the parameter in the methods has been passed by value, not by pointer or reference).
At the fourth line, nobody knows what C is. It is an unknown identifier.
This makes the definition of Visitor not valid, hence when you try to use your Visitor later another error occurs.
Problem is Class C is not defined at the point Visitor uses it. Either move it to the top (class C that is) or:
class C;
Add the above forward declaration at top of file. Since you only use it as a reference param, this should suffice.
Related
I have a class A and class B which both have the same methods and variables, but B has one additional variable (which is completely independent from other class members).
So it would be something like:
class A
{
void Foo();
bool m_var;
}
template< class T >
class B< T >
{
// Same stuff
void Foo();
bool m_var;
// Unique stuff
T m_data;
}
Normally, I would use inheritance B : public A, but I want to keep these classes super tight and I don't want to have vtable ptr inside them (as I'm not gonna use polymorphy anyway). What's the best approach to achieve that? I was thinking about templates and their specialization - having class A<T> and A<void>, but I need to remove something, not add. Is there any smart template trick which I could use?
I was also thinking about creating base class (without virtual dtor) with all common functionalities as a private nested class and inherited classes A< T > : public Base and empty B : public Base as public nested classes. It wouldn't allow anyone from outside to use base class ptr, but it doesn't sound like the purest solution... Is there any "valid" solution for my problem?
As long as you don't use the word virtual, you won't get a vtable. But you're right to think that inheritance is an awkward solution to this problem. Languages like Rust, Scala, and Haskell have a unit type () for data we don't care about. C++ approximates this (albeit poorly) with void, but it really only works as a function return type. My recommendation is to create your own well-behaved unit type.
struct Unit {};
Nice, empty type. There's only one meaningfully distinct instance of Unit, namely Unit(). Then A is just B<Unit>. The Unit m_data in B<Unit> contains no actual information and will likely be optimized out by the compiler.
As already answered, vtable pointers are only added to a class when they are needed. As long as there is nothing marked as virtual anywhere in either your base or derived class, the compiler will not generate a vtable for your type.
If you want to reuse A when writing B, why can't you just use plain old composition?
class A {
bool _var;
public:
explicit A(bool v);
void foo();
// accessors, which could be constexpr
bool var() const; // get
void var(bool n_v); // set
};
template<class T>
class B {
T _data;
A _a;
public:
B( /* params */);
void foo() { this->_a.foo(); }
// forward to A
bool var() const { return this->_a.var(); } // get
void var(const bool n_v) { this->_a.var(n_v); } // set
// add more stuff here
};
If you really are into nasty shenanigans, you might consider taking the private inheritance route, which is functionally the same thing (but less clean, IMHO):
template<class T>
class B : private A {
T _data;
public:
B( /* params */);
using A::foo; // reexports A::foo() as B::foo()
// generates
// - bool B::var()
// - void B::var(bool)
using A::var;
// add more stuff here
};
When I inherit from a class the compiler has to know the definition of the base class in order to create it. But when I inherit from a template class using oneself (the inheriting class), how can the compiler create the code? It does not know the size of the class yet.
#include <iostream>
template <class T> class IFoo
{
public:
virtual T addX(T foo, double val) = 0;
// T memberVar; // uncomment for error
};
class Foo : public IFoo<Foo>
{
public:
Foo(double value)
: m_value(value) {}
Foo addX(Foo foo, double b) override
{
return Foo(foo.m_value + b);
}
double m_value;
};
int main()
{
Foo foo1(1);
Foo foo2 = foo1.addX(foo1, 1);
std::cout << foo2.m_value;
}
First I thought it works because it's an interface but it also works with a regular class.
When I store the template as a member i get an error that Foo is undefined, just as I expected.
The general concept here is called the Curiously Recurring Template Pattern or CRTP. Searching on that will get lots of hits. see: https://stackoverflow.com/questions/tagged/crtp .
However there is a simple explanation that likely answers your question without getting too much into CRTP. The following is allowed in C and C++:
struct foo {
struct foo *next;
...
};
or with two types:
struct foo;
struct bar;
struct foo {
struct bar *first;
...
};
struct bar {
struct foo *second;
...
};
So long as only a pointer to a struct or class is used, a complete definition of the type doesn't have to be available. One can layer templates on top of this in a wide variety of ways and one must be clear to reason separately about the type parameterizing the template and its use within the template. Adding in SFINAE (Substitution Failure Is Not An Error), one can even make templates that do no get instantiated because things cannot be done with a given type.
With this definition of template class IFoo, the compiler does not need to know the size of Foo to lay out IFoo<Foo>.
Foo will be an incomplete class in this context (not "undefined" or "undeclared") and usable in ways that any incomplete type can be used. Appearing in a member function parameter list is fine. Declaring a member variable as Foo* is fine. Declaring a member variable as Foo is forbidden (complete type required).
how can the compiler create the code?
Answering this question would be the same as answering this question: How can the compiler compile that?
struct Type;
Type func(Type);
Live example
How can you define a type that doesn't exist and yet declare a function that use that type?
The answer is simple: There is no code to compile with that actually use that non-existing type. Since there is no code to compile, how can it even fail?
Now maybe you're wondering what is has to do with your code? How does it make that a class can send itself as template parameter to it's parent?
Let's analyze what the compiler see when you're doing that:
struct Foo : IFoo<Foo> { /* ... */ };
First, the compile sees this:
struct Foo ...
The compiler now knows that Foo exists, yet it's an incomplete type.
Now, he sees that:
... : IFoo<Foo> ...
It knows what IFoo is, and it knows that Foo is a type. The compiler now only have to instanciate IFoo with that type:
template <class T> struct IFoo
{
virtual T addX(T foo, double val) = 0;
};
So really, it declares a class, with the declaration of a function in it. You saw above that declaring a function with an incomplete type works. The same happens here. At that point, Your code is possible as this code is:
struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
So really there's no sorcery there.
Now let's have a more convincing example. What about that?
template<typename T>
struct IFoo {
void stuff(T f) {
f.something();
}
};
struct Foo : IFoo<Foo> {
void something() {}
};
How can the compiler call something on an incomplete type?
The thing is: it don't. Foo is complete when we use something. This is because template function are instantiated only when they are used.
Remember we can separate functions definition even with template?
template<typename T>
struct IFoo {
void stuff(T f);
};
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
struct Foo : IFoo<Foo> {
void something() {}
};
Great! Does it start looking exactly the same as your example with the pure virtual function? Let's make another valid transformation:
template<typename T>
struct IFoo {
void stuff(T f);
};
struct Foo : IFoo<Foo> {
void something() {}
};
// Later...
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
Done! We defined the function later, after Foo is complete. And this is exaclty what happens: The compiler will instanciate IFoo<Foo>::stuff only when used. And the point where it's used, Foo is complete. No magic there either.
Why can't you declare a T member variable inside IFoo then?
Simple, for the same reason why this code won't compile:
struct Bar;
Bar myBar;
It doesn't make sense declaring a variable of an incomplete type.
Let's say I have a nice looking base class called base:
class base
{
public:
virtual void foo() const = 0;
};
Now, I have a class named foo that I would like to inherit from base and override base::foo:
class foo : public base
{
public:
virtual void foo() const override;
};
This is illegal in C++, as you are not allowed to name a method the same thing as the class (C++ greedily believes methods with the same name as the class are constructors, which are not allowed to have return types). Is there any way around this that doesn't involve changing the name of the class or method? I want external users to be able to create foo classes without the knowledge that there is a method base::foo called by someone else (imagine foo can be both a noun and a verb).
Is there any way around this that doesn't involve changing the name of the class or method?
No, there isn't.
All methods named foo are special in class foo -- they are constructors. Hence, they cannot be overridden virtual member functions.
I'll take a wild guess and just say NO.
You can have a lot of ambiguities in C++ (that sometimes have to be explicitly disambiguated), but I don't even see a way how a compiler or programmer could disambiguate this situation. Well, A programmer can (a function with a return type is obviously not a constructor), but C++ can't.
In C++, the only method that can have the class' name is its constructor.
So, no. You can't.
Okay, here's my (slightly evil) solution...
// Create an intermediate class which actually implements the foo method:
class foo_intermediate : public base
{
public:
virtual void foo() const override;
};
// Derive from that class and forward the constructor along
class foo : public foo_intermediate
{
public:
using foo_intermediate::foo_intermediate;
private:
friend class foo_intermediate;
// Actual implementation for the foo function goes here
void foo_impl() const;
};
// In some CPP file:
void foo_intermediate::foo() const
{
// Need to access the typename foo via namespace (global here)
static_cast<const ::foo*>(this)->foo_impl();
}
Actually calling foo is a bit funny, since this can't work:
void bar()
{
foo x;
x.foo(); // <- illegal attempt to access to the foo constructor
}
You must access through an alias:
void baz()
{
foo x;
base& rx = x;
rx.foo(); // legal
}
As an alternative, you can use a typedef:
class foo_impl : public base
{
public:
virtual void foo() const override;
};
using foo = foo_impl;
This gets around the issue of calling x.foo(), since it no longer appears as a constructor access.
I made a Gist so others could play with the two solutions if they are so inclined.
I'm getting this strange problem which I don't know why happens. The first and second of the following code snippets compile, while the third does not:
Compiles:
class Foo {
public:
Foo() { Bar(); }
private:
class Bar {};
};
Compiles:
class Foo {
class Bar {}; // Or only forward declare here and define later
public:
Foo(Bar) {}
}
Does not compile:
class Foo {
public:
Foo(Bar) {}
private:
class Bar {};
};
What makes the third fail to compile while the first can?
Normally, in C++, you can only reference declarations that were previously made in the translation unit. However, within a class definition, the definition of member functions are allowed to reference declarations which are made later in the class. Basically, the compiler restructures your in-class definitions so that they work as though they were written just after the class.
But this is only true of the function definitions. The declaration of the function (including parameter types) isn't allowed to do this. They can only reference declarations that have already been made in file order.
So you can do this:
class Test
{
public:
void Func(int x) {Inner foo;}
private:
class Inner {};
};
But not this:
class Test
{
public:
void Func(Inner x) {}
private:
class Inner {};
};
First example does not expose anything about private Bar to the outside, while third does.
Third example is pretty much saying, that there exist some class Foo, which has constructor with single argument of type Bar. But Bar is unknown to the outside. Imagine calling such constructor.
Foo f{Foo::Bar{}};
Will result probably in something like Foo::Bar is inaccessible.
Just a small annoyance really as I can work around the problem by wrapping the derived function instead of using the 'using' keyword but why doesn't the following work (the compiler tells me that 'get_elem' is still pure virtual in 'Bar' class).
class Elem {};
class DerivedElem : public Elem {};
class Foo {
public:
virtual Elem& get_elem() = 0;
};
class Goo {
protected:
DerivedElem elem;
public:
DerivedElem& get_elem() { return elem; }
};
class Bar : public Foo, public Goo {
public:
using Goo::get_elem;
};
int main(void) {
Bar bar;
}
Cheers,
Tom
If Goo is a "mixin" designed to implement the interface Foo in a particular way (there could be other mixins with other implementations), then Goo can derive from Foo (instead of Bar doing so).
If Goo isn't designed to implement the interface Foo, then it would be a terrible mistake to treat Bar as though it had implemented that pure virtual function, when it fact it just happens to have a function of the same signature. If you want implicit interfaces and "duck" typing in C++ you can do it, but you have to do it with templates. Rightly or wrongly, pure virtual functions are for explicitly declared interfaces, and Goo's get_elem function is not explicitly declared to implement Foo::get_elem. So it doesn't.
I guess that doesn't explain why in principle the language couldn't define using Goo::get_elem for Foo;, or some such declaration in Bar, to avoid the need for Bar to contain a lot of boilerplate wrapping the call.
You can maybe do something with templates to allow Goo to support this to some extent, without really knowing about Foo:
template <typename T>
class Goo : public T {
protected:
DerivedElem elem;
public:
DerivedElem& get_elem() { return elem; }
};
class Bar : public Goo<Foo> {};
class Baz : public Goo<Fuu> {};
Where Fuu is some other interface that has a get_elem function. Obviously it's then the responsibility of the author of Bar to ensure that Goo really does implement the contract of Foo, and the same for Baz checking the contract of Fuu.
By the way, this form of covariance is a bit dodgy. Looking at Foo, someone might expect the expression bar.get_elem() = Elem() to be valid, and it isn't, so LSP is violated. References are funny like that. ((Foo &)bar).get_elem() = Elem() is valid but in general doesn't work! It only assigns to the Elem sub-object, and for that matter so does ((Foo &)bar).get_elem() = DerivedElem(). Polymorphic assignment is basically a nuisance.
In your example, the Foo and Goo are separate classes. In Bar, the method get_elem from Goo is not at all the same with the one in Foo, even if their signature match.
By having using Goo::get_elem, you simply tell the compiler to resolve unqualified call to get_elem() to the one in Goo.
You've encountered one of the many odd corners of C++. In this case C++ does not consider two virtual functions inherited from different classes to be the same function even though they have the same name and type signature.
There are some good reasons for C++ to act this way. For example, it's frequently the case that those two functions really aren't the same, despite the fact they have the same name and type signature. The semantic meaning of the two functions are different.
Here is an example:
namespace vendor1 {
class Circle {
public:
virtual ::std::size_t size() const { return sizeof(*this); }
};
} // namespace vendor1
namespace vendor2 {
class Shape {
public:
virtual double size() const = 0;
};
class Circle : public Shape {
public:
virtual double size() const { return radius_ * radius_ * M_PI; }
};
} // namespace vendor2
And then you try this:
namespace my_namespace {
class Circle : public ::vendor1::Circle, public ::vendor2::Circle {
// Oops, there is no good definition for size
};
So you have to resort to this:
namespace my_namespace {
class Vendor1Circle : public ::vendor1::Circle {
public:
virtual ::std::size_t data_structure_size() const { return size(); }
};
class Vendor2Circle : public ::vendor2::Circle {
public:
virtual double area() const { return size(); }
};
class Circle : public Vendor1Circle, public Vendor2Circle {
// Now size is still ambiguous and should stay that way
// And in my opinion the compiler should issue a warning if you try
// to redefine it
};
So, C++ has good reason to treat virtual functions with the same type signature (the return type is not part of the type signature) and name from two different bases as different functions.
As far as using goes... All a using directive says is "Add the names from this other namespace to this namespace as if there were declared here.". This is a null concept as far as virtual functions are concerned. It merely suggests that any ambiguity when using a name should be resolved a different way. It only declares a name, it doesn't define the name. In order for a virtual function to be overridden a new definition is required.
OTOH, if you put in a simple thunk redefinition inline like this:
class Bar : public Foo, public Goo {
public:
virtual DerivedElem& get_elem() { return Goo::get_elem(); }
};
a good compiler should see that and know to not even bother to create the function, and instead just fiddle the virtual table entries to do the right thing. It may need to actually emit code for it and have the symbol available in case its address is taken, but it should still be able to simply fiddle the virtual table into having the function completely disappear when called through a Foo *.