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.
Related
It is very easy that we can make sure derived class must implement interface defined in base class.
That is pure virtual function.
For example:
class BaseClass
{
...
virtual void print()=0;
...
}
class DerivedClass :public BaseClass
{
// function must be implement, otherwise compiler will complain ...
void print()
{
}
};
Can we defined a static interface in base class and make sure the interface must be implement in derivate class?
I want something like this
class BaseClass
{
...
static void print(); // base class only define static interface
...
}
class DerivedClass :public BaseClass
{
// derived class must implement interface, otherwise compiler will complain ...
static void print()
{
}
};
I have no idea about this.
Thanks for your time.
It is not possible to make a virtual static function. For the simple reason that when calling a static function, you always know the class that defines that function in compile time. Unlike virtual functions, where you don't know the type of the object whose method you're calling.
For example:
class A
{
public:
virtual void f() {printf("A");}
};
class B : public A
{
virtual void f() override {printf("B");}
};
void g(A& a)
{
a.f();
}
int main()
{
B b;
g(b);
return 0;
}
In the above example, inside the function g, the correct function is invoked (B::f). Even though while compiling the function it is not known what the type of its argument is (it could be A or any class derived from A).
Without making f() virtual, you would have overloaded the method f, rather than overridden it. Which means that in the following example, the output would be "A", even though you might expect it to be "B":
class A
{
public:
void f() {printf("A");}
};
class B : public A
{
void f() {printf("B");}
};
void g(A& a)
{
a.f();
}
int main()
{
B b;
g(b);
return 0;
}
This may cause serious bugs, and it is suggested to never overload base class methods, and to always use the override keyword when overriding a virtual method to escape those bugs.
When making a static function, you can simply overload it, it would not create a compilation error. However, you probably never should overload it, because it may hide a bug that is very difficult to track (you are certain that B::f() is being called while actually A::f() is being called).
Furthermore, it is not possible to 'force' the derived class to implement a static interface, because there is no such thing as a static interface. Because you have no virtual static functions, you may not pass a reference or pointer to the interface that would implement this function.
Suppose I have a class Foo
class Foo{
public:
bool virtual bar(){return false;}
};
And class FooFoo inheriting Foo. bar() is not overriden in class FooFoo. I cannot change the headers of Foo or FooFoo. Is it then at all possible to override the default implementation of bar() in FooFoo?
This is impossible; you can't modify a class without modifying it, as it were.
Your best option is probably to publicly inherit from FooFoo and override in the derived class.
Is it then at all possible to override the default implementation of
bar() in FooFoo?
No, but you could derive another class, and use that class "polymorphically" via the base. This should have the same effect, given that the original client of Foo does his work through the interface of Foo, as he should
Therefore:
//In Foo.h - may not be modified
struct Foo
{
virtual bool bar(){ return true;}
};
//In FooFoo.h - may not be modified, hence no override...
struct FooFoo: public Foo
{
virtual bool bar(){/**/}
};
//FooFoo_2 - The new class - may be implemented in terms of FooFoo
struct FooFoo_2: public Foo
{
virtual bool bar() override{/*new implementation*/}
};
void fooUser( Foo& foo )
{
bool result = foo.bar();
if (result ){} //etc
}
int main()
{
FooFoo_2 theNewImplementation;
fooUser( theNewImplementation );
return 0;
}
Note also that "override" is not required, but if added, one would get a compiler error if the signature of bar changes in base (which would cause derived to not be virtual anymore) - something that one would want to be aware of.
Regards
No. You can only override a function by declaring the override within the derived class's definition.
In C++ language no. In particular implementation it is technically possible to manually modify vtable for class FooFoo and replace pointer to Foo::bar() to something else. Of course this would be an ugly hack and neither recommended practice in any sense nor guaranteed to work even when something changes (for example compilation flags).
No. You'll need to declare the override in the FooFoo class definition, which you said you cannot do. If you tried to define the overriden function in FooFoo, outside of the class, you'd run into errors, since it was not previously declared to be overriden in FooFoo.
Also note, in C++11 and later, you should use the override attribute. Example:
struct FooFoo : Foo
{
bool bar() override { return true; }
};
What does it mean to have a using inside a class definition?
class myClass {
public:
[...]
using anotherClass::method;
};
That declaration unhides a base class member. This is most often used to allow overloads of a member function. Example:
class Base {
public:
void method() const;
};
class Derived : public Base {
public:
void method(int n) const;
// Without the using, you would get compile errors on d.method();
using Base::method;
};
The case I've seen it:
class A
{
void foo(int);
void foo(float);
}
class B : public A
{
void foo(string);
}
B b;
b.foo(12); // won't work!
Because I have implemented a new foo function in B with a different signature it hides the foo functions from A. In order to override this behavior I would do:
class B : public A
{
void foo(string);
using A::foo;
}
Most often, syntax like this is used like so:
class derived : public base {
public:
[...]
using base::method;
};
The using declaration here unhides a member declaration from the parent class. This is sometimes necessary if another member declaration in derived may hide the member from base.
If anotherClass is a base class that contains a member function like
virtual void f();
and you decide to overload the function in the derived class like
virtual void f(int);
it "hides" f() in the base class. Calling f() through a pointer to the derived class for example, would result in an error, since the compiler does not "see" the version of f() taking no arguments from the base class anymore.
By writing
using Base::f;
you can bring the base classes function back into scope, thus enabling overload resolution as you might have expected it to work in the first place.
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 *.
Let's say I have the following class hierarchy:
class Base
{
protected:
virtual void foo() = 0;
friend class Other;
};
class Derived : public Base
{
protected:
void foo() { /* Some implementation */ };
};
class Other
{
public:
void bar()
{
Derived* a = new Derived();
a->foo(); // Compiler error: foo() is protected within this context
};
};
I guess I could change it too a->Base::foo() but since foo() is pure virtual in the Base class, the call will result in calling Derived::foo() anyway.
However, the compiler seems to refuse a->foo(). I guess it is logical, but I can't really understand why. Am I missing something ? Can't (shouldn't) it handle this special case ?
Thank you.
When you qualify a method name with a class name, as in Base::foo() dynamic dispatch (run-time binding) does not apply. It will always call the Base implementation of foo(), no matter if foo() is virtual or not. Since in this case it is pure virtual, there is no implementation and the compiler complains.
Your second problem is that in C++, friendship is not inherited. If you want Other to have special access to Derived, it needs to be a friend of Derived specifically.
This, on the other hand, works:
Base* a = new Derived();
a->foo();
Because here, you are calling foo() on a Base* where foo() is public, and since you are not qualifying foo() with a class name, it uses dynamic dispatch and ends up calling the Derived version of Foo.
I guess You could do this
void bar()
{
Base* a = new Derived();
a->foo();
};
However, the compiler seems to refuse that.
Refuse what? It sounds like you are saying that the compiler is refusing to allow Other to call the foo() function through a Base pointer. That certainly shouldn't be the case.
To answer your basic question, friendship is not inherited....period. Permission scope is checked at the same stage as name resolution and since foo() is protected within the names you are using, you can't call it.
Polymorphism on the other hand is resolved through pointer redirection and has nothing to do with name resolution or access permission.
Try put this "friend class Other;" in the derived class.
Update: Now think of it, I agree with Tyler that you should change a to a Base pointer.
Base* a = new Derived();
It's unfortunate, but friendliness is inherently broken in C++ in my opinion:
Not inherited
Give unrestricted access to all the internals, no possibility to restrict it
I've given up using it "as-is" and I now mostly use the Key pattern (for lack of a better name).
///
/// Key definition
///
class Friend;
class FriendKey: boost::noncopyable { friend class Friend; FriendKey() {} };
///
/// Base/Derived definition
///
class Base
{
public:
void mySpecialMethod(const FriendKey&) { this->mySpecialMethodImpl(); }
private:
virtual void mySpecialMethodImpl() = 0;
}; // class Base
class Derived: public Base
{
public:
private:
virtual void mySpecialMethodImpl() {}
}; // class Derived
///
/// Friend definition
///
class Friend
{
public:
void mySpecialCall()
{
Derived d;
d.mySpecialMethod(FriendKey());
}
}; // class Friend
The concept is simple: each class declares a key (possible even in the forward header), and those that wish to grant special access to them will only make it possible for this key.
It's not perfect, because you can of course abuse it (by transitivity of the key). But then in C++ you can abuse everything, so it's more a problem of protected against Murphy than Machiavelli.