Virtual inheritance weirdness (code)
final by changing the scope of an inheritance. I got some weird results.
class base {
public:
virtual int foo() = 0;
};
class middle: public base {
private:
int foo() { return 5; }
};
class final: public middle {
public:
int foo() { return 10; }
};middle::foo is private, and a caller can call final::foo() but can't call middle::foo(). Further, if I make base::foo private, the code still compiles fine, but if I make base::foo private and give it an implementation, it (correctly) fails to compile because middle is trying to override a private method. (But if base::foo is public and implemented and middle::foo is private, final can still override it, indicating that it's using base's access rule.)Is this tomfoolery in g++ or in the C++ spec? Obviously, private inheritance on a pure abstract method is a completely meaningless idea (and in that respect, that should be an error), but it seems like a class's method access rules should respect the immediate parent's, not the base class's. Either that or virtual inheritance should not allow access changes at all to begin with.
The use case in this particular circumstance is that I have a base interface class (pure virtual), an intermediate partial implementation class, and then a bunch of derivatives from that intermediate class, which I would rather not be able to override some of the bits that the intermediate class implements. i.e. I want something like Java's final keyword.
I guess the only reasonable C++ solution is to add a big @note to the intermediate class's documentation saying to not override these methods.
Comments
Changing access levels is a tool, not a mistake, and doesn't need a warning.
The lesser thing which is what started this post is that a class is able to change an access level from public to private, then a further derived class is able to take it back to public, which is also anathema to the point to private (vs. protected).
Whether or not this leads to situations that don't seem to make sense is beside the point. As we all know, C++ is designed to let people do all sorts of things that don't make sense. Don't look for Java style programmer protection.
private:
virtual void foo() = 0;
};
class B {
public:
virtual void foo() {}
};
And anyway, the multi-level inheritance issue still leads to an inherent inconsistency. A private method or member is supposed to be completely private, including to derived classes. Does the C++ spec say that the access level for inheritance is based on the first appearance of the member, or based on it in the parent?
"private" and "public" specify whether you can call it, not whether you can derive from it. Yes, it makes no sense to have something that can't be called "private", but that's what falls out of not having to individually label things as private as in Java.
I'm also not convinced that it is entirely silly: Consider:
class A {
private:
virtual void foo() = 0;
public:
doIt()
{
foo();
}
};
class B : public A{
public:
virtual void foo() {}
};
class C : public A{
private:
virtual void foo() {}
};
int main()
{
A *a = new b;
a->doIt();
// a->foo(); // NOT ALLOWED
B *b = new b;
b->foo(); // ALLOWED
}
I can see where this sort of thing might be useful. In this case, the private abstract has a very real meaning, that is, you can't call it from a base class pointer directly.