Reputation: 239
class A
{
public:
void virtual magic() = 0;
void bar()
{
magic(); // this should be legal
}
};
class B: public A
{
public:
void magic()
{
cout<<"implement magic here"<<endl;
}
};
class C: public B
{
void foo()
{
magic(); // this should not be allowed, i.e. create compile-time error
}
};
Thus the pure virtual base class A
of B
shall have access to magic()
, but not any derived class C
of B
. Can this be achieved using access specifiers and/or friend declarations or in any other way?
Upvotes: 4
Views: 1363
Reputation: 98425
What you really want is most likely to separate the public interface from the implementation detail of inheritance, using so-called Template Method pattern.
Your public interface should use non-virtual methods. The virtual methods should all be private. Then the interface in the base class can enforce invariants and do boilerplate work. The derived classes can still override the virtual method, they just can't call it directly.
Only if the derived classes need to invoke the base implementation of a virtual method, make the virtual method protected. That's almost all.
The base class destructor should be either public and virtual, or protected and nonvirtual. The former when you wish to perform destruction using the base class interface. Now that's really all :)
Concretely:
#include <iostream>
#include <cassert>
using namespace std;
class A
{
// we do magic without sprinking any dust, but optionally we could sprinkle some beforehand
void virtual sprinkle() {};
void virtual magic(int) = 0;
public:
void doSomeMagic(int power) {
assert(power > 3 and power < 8);
sprinkle();
magic(power);
}
virtual ~A() {}
};
class B: public A
{
void magic(int power) {
cout << "B: did magic of with power=" << power << endl;
}
};
class C : public B
{
void sprinkle() {
cout << "C: also sprinked some dust before doing the magic" << endl;
}
};
int main()
{
B b;
C c;
b.doSomeMagic(5);
c.doSomeMagic(6);
return 0;
}
B: did magic of with power=5
C: also sprinked some dust before doing the magic
B: did magic of with power=6
Upvotes: 2
Reputation: 3801
As Dave S's comment suggests, change the access specifier of C::magic():
class A
{
public:
void virtual magic() = 0;
};
class B: public A
{
public:
void magic()
{
cout<<"implement magic here"<<endl;
}
};
class C:public B
{
private:
void virtual magic(){};
};
Upvotes: 0
Reputation: 234635
If you have access to class A
, change the access of magic
to private
:
private:
void virtual magic() = 0;
Then make class B a friend of class A:
class A
{
friend class B;
Upvotes: 4
Reputation: 500177
Basically, you cannot reduce the visibility of a virtual method. Once it's public in A
, there's no tidy way to make it protected or private in any of the derived classes.
Upvotes: 7