In C++ (11/14/17, I don't care), I have a base class B which exposes method x as protected.
In class D1, which derives from B, I want to prevent further descendants (of D1) from calling x(). Now, if I were overriding x in D1, I would simply mark it as final.
But, what if D1 does not override x(), yet D1 still wants to hide it from descendants? How can I do that?
How can I do that?
By changing the program and overriding x in D1. You can just delegate to the base class version by calling it.
Related
Suppose base class B has a nonvirtual public function f() , which is unfortunately overridden by derived class D.
Then there's a D object d passed to a B pointer pB.
Is there a way to prevent calling pB->f()?
If you can change B, you can either make f virtual, or make it forward to a virtual protected do_f, or various other things.
If you can't change B, you can't stop it's public method being called, and you can't somehow intercept a call to a non-virtual base class method.
Your question essentially asks, “How do I make a function virtual?” You don’t give a reason why you can’t just do that, but maybe you can’t change the declaration of B.
If B has at least one virtual function, you could use RTTI to check if *pB is really a D and cast it to D& if so. You cannot make existing code that takes a B* do so; if your daughter class breaks when you call it as a B, it breaks the contract of that interface.
Otherwise, it might be possible to determine that *pB is a D somehow by calling the B interface, but that would be some rigmarole specific to B and D.
C++: I have a base class A with a pure virtual function f() and then two classes B and C inherit virtually from A, and a class D that inherits from both B and C (the typical diamond structure):
A f() = 0
v/ \v
B C
\ /
D
Where and when does f() = 0 need to be implemented in the following cases?
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?)
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
Neither B nor C have pure virtuals of their own (-> possible way to skip implementation in B and C and "pass it through" to D?)
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implement f()? In which cases, if any, is it not possible for D to implement f()?
Are there any other common suggestions for these kind of problems?
Thanks.
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?)
Yes D MUST implement ALL the inherited pure virtual functions.
Unless a class implements all the pure virtual functions of the classes it derives from the class itself actas as an Abstract class.
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
D will have to implement the pure virtual function it inherits through its Base classes in any hierarchy. If its immediate Base class does not define a Pure virtual function, then that class becomes an Abstract class too, and unless D implements the inherited pure virtual function, it will become Abstract too.
Neither B nor C have pure virtuals of their own (-> possible way to skip implmentation in B and C and "pass it through" to D?)
D will have to implement the the pure virtual functions it inherits through A->B & A-C.Note that in this case both B and C will be Abstract classes.
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implment f()? In which cases, if any, is it not possible for D to implement f()?
D needs to implement foo() in all the above 3 conditions, to be able to be instantiable(Non-Abstract).
Conclusion:
A class needs to implement ALL the pure virtual functions it inherits from ALL it's base classes, failing to do so will make the class an Abstract class.
Virtual attribute is inherited, If a Super class declares a function virtual then the overridden function in the derived class is virtual too and it passes down the virtual attribute to all classes deriving from it.
Avoid the Diamond of Death! Unless you really understand the subtleties involved with it. A lot of people try to use virtual Inheritance when it is not really the most apt way to achieve what their design wants to achieve. The use of Virtual Inheritance is indeed necessary in some scenarios, it is nevertheless an important construct provided by the language, but more often used in wrong ways. So it makes sense to revisit your design once to verify if you really need virtual Inheritance.
Following might be a good read:
Multiple Inheritance - Part I
Multiple Inheritance - Part II
Multiple Inheritance - Part III
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?
Yes. Any class that is inherited from abstract class must implement virtual functions to be able to instantiate. Or else they will also be abstract.
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
Since C also derived from A, it should also implement f().
Neither B nor C have pure virtuals of their own (-> possible way to skip implmentation in B and C and "pass it through" to D?)
You can do that. But that prevents instantiation of B or C alone like -
A *obj = new B(); // Error
A *obj = new C(); // Error
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implment f()? In which cases, if any, is it not possible for D to implment f()?
f() can be implemented in D alone as long as you do want all of it's parent classes to be abstract.
The only requirement is that at the "leaf" level (the most derived one) everything has an implementation (and possibly one only, otherwise ambiguity can arise if -at the point you access the graph- there are more implementation at a same "distance".
So D must implement everything has not been implemented yet, or everything has been implemented more than once through different paths (to disambiguate).
If something -at D level- is still left unimplemented ... D cannot be instatiated, and the implementation is demanded to and E, derived from D.
- Diamonds are forever -
No, abstract classes (presumably B and C) don't need to implement inherited pure virtuals. A child class like D will need to do so to be instantiated though.
No, again B and C will inherit the pure virtual method and it need only be overridden to generate a final concrete class.
Yes, this would pass through implementation to D, in one of two ways. If B and C both inherit virtually, then D would implement it once. If they don't inherit virtually then D would need to override both the B and C versions of f to be concrete.
If D is abstract it never needs to implement f. Assuming you mean it to be concrete, in all three cases you'd need to override f in D. Only if both B and C override f would D not need to.
Take a long look at your design and remove the diamond inheritance. In most cases that's going to be your best bet to prevent all these sorts of issues.
I have seen this question http://www.careercup.com/question?id=384062
class Base {
public :
virtual void method () = 0;
private :
int n;
};
void Base::method() { n = 1;}
class D1 : Base {};
class D2 : public D1 {
int i;
void method() {i = 2;}
};
It passed the compiler of vs2008 and g++ 4.4.3
Here is my understanding of above code, please correct me if I am wrong
S1> D1 has inherited variable Base::n but it cannot access it.
S2> D1 has inherited the function Base::method but it doesn't call/modify this inherited function in the above implementation.
S3> D2::method is not an overridden version of D1::method
S2 and S3 are wrong.
D1's methods can call it's Base::method(), but other code can't as Base part of D1 is private.
Base::method() is overridden by D2. If you somehow convert (new D2) to (Base*) and call Base::method, the i=2 code will run.
Considering access control, if you have pointer to Base*, external code can use ->method() because it's public, and if you have pointer to D2*, ->method() can't be called because it's private, even if it's the same object and the same method.
Also, despite your (n=1) implementation for Base::method() it and its class remain abstract.
D1 has inherited variable Base::n but it cannot access it.
Correct.
Private members of a class are never accessible from anywhere except the members of the same class.
D1 has inherited the function Base::method but it doesn't call/modify this inherited function in the above implementation.
Correct, but conditonally, Read below for why:
D1 inherits the Base::method but it is not calling/invoking it because you did'nt add any statement to do so. But it can call it.
Pure virtual functions can have a body and they can be called by drived class members just like any other member function.
class D1 : Base
{
public:
void doSomething()
{
Base::method();
}
};
Note that in your Base class n is private so the only way to access it is through member function of Base & since only method() can do so, You can do it through it.
Note that presence of atleast one pure virtual function makes an class Abstract Class, And one cannot create objects of an Abstract class. Any class deriving from an Abstract class must override ALL the pure virtual functions of the Base class or else the derived class becomes an Abstract class as well.
Based on above rule,
In your case both Base and D1 are Abstract classes.
D2::method is not an overridden version of D1::method
Incorrect
Though method() is not acessible to the ouside world through instance of class D1, it is still very much a part of it. Access control dictates access rights not presence or absence of members.
So, Yes, D2::method is an overriden version of D1::method and it hides it as well, just that in this case, D1::method was not acccessible in the first place
In this case both Base and D1 classes are abstract classes which cannot be instantiated.
S1 - yes
S2 - Yes D1 has inherited the function. Can you please clarify your question.
S3 - No. D2::method is the override you have provided for the D2 class.
Edit:
I just noticed the private inheritance of D1 from Base class. In that case, S1 and S2 still hold good.
Updated: S3: D2::method is both overriding and hiding the base class method.
S1: Correct
S2: Correct
S3: Correct, more clearly D2::method hides D1::method
S1 - Correct
S2 - Sorry I'm not very clear what you meant. In D1 or subclasses you can define method() to override it in Base but cannot call it. And, D1* cannot be converted to Base* because of private inheritance.
S3 - Incorrect. Once you declare a member function as virtual in the base class, it will keep virtual in subclasses even you leave out virtual. So in your case, method() in D2 is a overridden version of D1::method() and Base::method().
I have the following code:
#include <iostream>
class Grandma
{
public:
virtual void foo() = 0;
};
class Mom : public Grandma{};
class Dad
{
public:
void foo() { std::cout << "dad's foo impl"; }
};
class Me : public Mom, public Dad{};
int main()
{
Me m;
m.foo();
}
and getting : cannot instantiate abstract class
I know what this error means, I know I can't instantiate Grandma because of pure-virtual.
But why can't I instantiate Me, when compiler knows I am derived from Mom and Dad and Dad has foo implemented?
I know I can fixed it by adding foo into Me and inside it call e.g. Dad::foo, but I am afraid it is not solution for my case.
Is it really necessary to have virtual method implementation between its declaration and instantiated object (when traversing "class hierarchy graph")? See ASCI graph
A
|
B1 B2
\ |
C1 C2
| /
|/
D
|
E
When I want to instantiate E and have virtual declaration in A, the only way to make it run is to define it in A, B2, C1, D or E?
and similarly when is virtual declaration in C2 only way is to define it in C2, D or E?
I know this may be silly question, but I had a loooong day and can not think anymore.
Please, do not answer just with - "It is not possible", but try to add explanation why not.
Thank you!
EDIT -- foo() in Dad is of course should not be private
There is no relation between Dad class and Grandma class. Dad and Grandma are two completely different classes. Given that the method in Dad is not considered as an implementation of the pure virtual method in Grandma and has to be implemented in the Me class.
When you derive from an Abstract class(class containing atleast one pure virtual function) the deriving class needs to override and implement ALL the pure virtual member functions of the Base Class. If not, the deriving class becomes Abstract too, same applies to the classes deriving from the derived class further down the hierarchy.
Unfortunately you're right that you have to implement the virtual method in the path between original declaration and final instantiated object. Objects multiply inherited in can't implement that interface.
So from the question it sounds like you're trying to implement a parent interface in a child class by inheriting from the implementor. Instead of that approach, did you consider instead having the parent class delegate the work to a strategy pattern and then select the proper strategy in your child class. Then you can still compose implementations together and don't have to worry about the many complexities of multiple inheritance.
You are correct that a virtual function is only overridden by implementations provided by classes inheriting (potentially through several layers) from the class where the virtual function is originally declared.
However, depending on what you are actually trying to accomplish, Sister Class Delegation may what you want. Basically, you can declare virtual functions in a base common to both Grandma and Dad ('Person'?) and Grandma can call those functions even if only Dad provides an implementation when you're using a Me object. Even though Grandma would know nothing about Dad, when you use virtual inheritance any subclasses your final class pulls in can be used to satisfy virtual functions from the virtual base class.
class Base{
public:
void setX(int a) {x=a;}
private:
int x;
};
class D1: protected Base{};?
class D2: public D1{};
what is the access level for the member function setX() in the class D2 ?
is it protected ? of private?
Can any kind people explain this, I mean how to judge access level regarding inherence ....something like this. thank you!
Edited: Add on more question
but WHy I cannot call : d2.setX() ? d2 is a instance of D2. It turns out compiler error – user658213 0 secs ago edit
SetX is protected and x is inaccessible from D2. You can only restrict access, you cannot broaden it.
setX becomes protected via protected inheritance in D1, and remains protected through public inheritance in D2. Thus, its final access level in D2 is protected.
The reason you would not be able to call setX would depend on the calling context. If you are calling from outside of a class derived from Base or D1 (e.g. D2), then you wouldn't be able to call it for the same reason you can not call any protected members - they are only for use by derived classes.