Can I somehow create a new subclass method in C++ with the same name as a virtual one in base class, but stopping inheritance?
Let me explain it with some more details, consider this code:
#define L(m) std::cout << m << std::endl;
class A {
public:
virtual void func() { L("A::func"); };
virtual void func2() { L("A::func2"); };
};
class B: public A {
public:
void func() { L("B::func"); }; //implements A::func
void func2(){ L("B::func2"); }; //implements A::func2
};
class C: public A {
public:
void func2() { L("C::func2"); }; //implements A::func2
void func() { L("C::func"); }; //meant to declare a new function but accidentally overrides A::func
};
I don't want to declare func as final in A (I know it would stop inheritance, but I need that for class B).
Also I want to call C::func2 with A:
C c;
A* a = &c;
a->func2(); //must use C::func2 (standard inheritance)
a->func(); //must use A::func !!! (possible?)
c.func2(); //must use C::func2
c.func(); //must use C::func
Obviously I can rename C's func to something else but anyway, is this somehow achievable without completely abusing C++ norms?
Try this :
class C: public A {
public:
void func2() { L("C::func2"); };
void func(int i = 0) { L("C::func"); };
};
The C::func is hiding the A::func one with a different signature. I got this result :
C::func2
A::func
C::func2
C::func
Instead of this with your code :
C::func2
C::func
C::func2
C::func
Related
I am learning and playing around with inheritance and abstract classes. I've run into a predicament that I would appreciate some clarifications on.
I am trying to override a non-virtual function from an abstract grandparent class. I am getting an error saying that 'member function declared with 'override' does not override a base class member.
I can call the original non-virtual function from child class instances in main(), but not override them in child classes?
Here's the code.
UPDATE:
Error went away when I marked the function as virtual, I would still appreciate an explanation as to why that virtual is necessary?
#include <iostream>
using namespace std;
class A
{
public:
virtual string GetClassName() = 0;
void foo(); // <--- this is the problem function
{
cout << "foo" << endl;
}
};
class B : public A
{
public:
string GetClassName() override
{
return "B";
}
};
class C1 : public B
{
public:
string GetClassName() override
{
return "C";
}
};
class C2 : public B
{
public:
void foo() override // ERROR:member function declared with override does not override a base class member.
{
cout << "foo c1" << endl;
}
};
// testing interface
void printName(A* ptr)
{
cout << ptr->GetClassName() << endl;
}
int main()
{
B* b = new B();
C1* c1 = new C1();
C2* c2 = new C2();
printName(b); // prints B
printName(c1); // prints C
printName(c2); // prints B
b->foo(); // prints foo, inherited directly from abstract class
c1->foo(); // prints foo, inherited directly from abstract class
c2->foo(); // ??
}
You cannot override a non-virtual function. It is as simple as that.
Methods in child classes can hide methods of parent classes when they have the same name, for example:
struct A {
void foo(){}
};
struct B : A {
void foo() {}
};
But thats not overriding. To override the method must be virtual. Thats one of the conditions that the override specifier helps to check:
struct A {
virtual void foo(){}
};
struct B : A {
void foo() override {} // <- error if A::foo is not virtual
};
PS: I have seen poor tutorials, that use the first example and call that overriding. Thats just wrong.
Can I have a virtual function in the base class and some of my derived classes do have that function and some don't have.
class A{
virtual void Dosomething();
};
class B : public A{
void Dosomething();
};
class C : public A{
//Does not have Dosomething() function.
};
From one of my c++ textbook:
Once a function is declared virtual, it remains virtual all the way down the inheritance, even if the function is not explicitly declared virtual when the derived class overrides it.
When the derived class chooses not to override it, it simply inherits its base class's virtual function.
Therefore to your question the answer is No. Class c will use Class A's virtual function.
Derived classes do not have to implement all the virtual functions, unless it is a pure virtual function. Even in this case, it will cause an error only when you try to instantiate the derived class( without implementing the pure virtual function ).
#include <iostream>
class A{
public :
virtual void foo() = 0;
};
class B: public A{
public :
void foo(){ std::cout << "foo" << std::endl;}
};
class C: public A{
void bar();
};
int main() {
//C temp; The compiler will complain only if this is initialized without
// implementing foo in the derived class C
return 0;
}
I think the closest you might get, is to change the access modifier in the derived class, as depicted below.
But, I would consider it bad practice, as it violates Liskov's substitution principle.
If you have a situation like this, you might need to reconsider your class design.
#include <iostream>
class A {
public:
virtual void doSomething() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
void doSomething() override { std::cout << "B" << std::endl; };
};
class C : public A {
private:
void doSomething() override { std::cout << "C" << std::endl; };
};
int main(int argc, char **args) {
A a;
a.doSomething();
B b;
b.doSomething();
C c;
//c.doSomething(); // Not part of the public interface. Violates Liskov's substitution principle.
A* c2 = &c;
c2->doSomething(); // Still possible, even though it is private! But, C::doSomething() is called!
return 0;
}
I tried this code:
class A
{
virtual void foo() = 0;
};
class B
{
virtual void foo() = 0;
};
class C : public A, public B
{
//virtual void A::foo(){}
//virtual void B::foo(){}
virtual void A::foo();
virtual void B::foo();
};
void C::A::foo(){}
void C::B::foo(){}
int main()
{
C c;
return 0;
}
It is OK when using the commented part, but when I try to write the definitions outside the class declaration, the compiler reports errors.
I am using the MSVC11 compiler, does anyone know how to write this?
I need to move the code into the cpp file.
Thank you~~
A function overrides a virtual function of a base class based on the name and parameter types (see below). Therefore, your class C has two virtual functions foo, one inherited from each A and B. But a function void C::foo() overrides both:
[class.virtual]/2
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.
As I already stated in the comments, [dcl.meaning]/1 forbids the use of a qualified-id in the declaration of a (member) function:
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers [...]"
Therefore any virtual void X::foo(); is illegal as a declaration inside C.
The code
class C : public A, public B
{
virtual void foo();
};
is the only way AFAIK to override foo, and it will override both A::foo and B::foo. There is no way to have two different overrides for A::foo and B::foo with different behaviour other than by introducing another layer of inheritance:
#include <iostream>
struct A
{
virtual void foo() = 0;
};
struct B
{
virtual void foo() = 0;
};
struct CA : A
{
virtual void foo() { std::cout << "A" << std::endl; }
};
struct CB : B
{
virtual void foo() { std::cout << "B" << std::endl; }
};
struct C : CA, CB {};
int main() {
C c;
//c.foo(); // ambiguous
A& a = c;
a.foo();
B& b = c;
b.foo();
}
You've got just one virtual function foo:
class A {
virtual void foo() = 0;
};
class B {
virtual void foo() = 0;
};
class C : public A, public B {
virtual void foo();
};
void C::foo(){}
void C::A::foo(){}
void C::B::foo(){};
int main() {
C c;
return 0;
}
I stepped into the same problem and accidentially opened a second thread. Sorry for that. One way that worked for me was to solve it without multiple inheritance.
#include <stdio.h>
class A
{
public:
virtual void foo(void) = 0;
};
class B
{
public:
virtual void foo(void) = 0;
};
class C
{
class IA: public A
{
virtual void foo(void)
{
printf("IA::foo()\r\n");
}
};
class IB: public B
{
virtual void foo(void)
{
printf("IB::foo()\r\n");
}
};
IA m_A;
IB m_B;
public:
A* GetA(void)
{
return(&m_A);
}
B* GetB(void)
{
return(&m_B);
}
};
The trick is to define classes derived from the interfaces (A and B) as local classes (IA and IB) instead of using multiple inheritance. Furthermore this approach also opens the option to have multiple realizations of each interface if desired which would not be possible using multiple inheritance.
The local classes IA and IB can be easily given access to class C, so the implementations of both interfaces IA and IB can share data.
Access of each interface can be done as follows:
main()
{
C test;
test.GetA()->foo();
test.GetB()->foo();
}
... and there is no ambiguity regarding the foo method any more.
You can resolve this ambiguity with different function parameters.
In real-world code, such virtual functions do something, so they usually already have either:
different parameters in A and B, or
different return values in A and B that you can turn into [out] parameters for the sake of solving this inheritance problem; otherwise
you need to add some tag parameters, which the optimizer will throw away.
(In my own code I usually find myself in case (1), sometimes in (2), never so far in (3).)
Your example is case (3) and would look like this:
class A
{
public:
struct tag_a { };
virtual void foo(tag_a) = 0;
};
class B
{
public:
struct tag_b { };
virtual void foo(tag_b) = 0;
};
class C : public A, public B
{
void foo(tag_a) override;
void foo(tag_b) override;
};
A slight improvement over adigostin's solution:
#include <iostream>
struct A {
virtual void foo() = 0;
};
struct B {
virtual void foo() = 0;
};
template <class T> struct Tagger : T {
struct tag {};
void foo() final { foo({}); }
virtual void foo(tag) = 0;
};
using A2 = Tagger<A>;
using B2 = Tagger<B>;
struct C : public A2, public B2 {
void foo(A2::tag) override { std::cout << "A" << std::endl; }
void foo(B2::tag) override { std::cout << "B" << std::endl; }
};
int main() {
C c;
A* pa = &c;
B* pb = &c;
pa->foo(); // A
pb->foo(); // B
return 0;
}
Assuming that the base classes A and B are given and cannot be modified.
Let's consider two classes A and B with the following interface:
class A {
public:
virtual void start() {} //default implementation does nothing
};
class B {
public:
void start() {/*do some stuff*/}
};
and then a third class which inherits from both, A publicly because it implements this "interface", and B privately because that's implementation detail.
However, in this specific implementation, start() only has to contain a call to B::start(). So I thought I could use a shortcut and do the following:
class C: public A, private B {
public:
using B::start;
};
and be done with it, but apparently it doesn't work. So I get using private base function doesn't work in order to override virtuals. From that, two questions:
Is there any way to make this work as I supposed it may have worked?
Why would the compiler accept this code as valid? As I see it there are now two start() functions with the exact same signature in C and yet the compiler seems fine with it and only calls A::start().
EDIT: A few precisions:
The goal is to manipulate C objects through A pointers.
I'm currently using a simple function that just calls B::start(), I was specifically wondering if a using declaration could indeed "override" a virtual, and if not, how this was allowed to have both functions coexist.
I might have omitted a few things like virtual inheritance for simplicity.
Is there any way to make this work as I supposed it may have worked?
You should override the member function and explicitly call B::start():
class C: public A, private B {
public:
void start() override { B::start(); }
};
Why would the compiler accept this code as valid? As I see it there
are now two start() functions with the exact same signature in C and
yet the compiler seems fine with it and only calls A::start().
You are right, there are two member functions accessible in C (A::start() and B::start()). And in class C, without overriding start() or making the start() of any of the base classes visible by doing a using ...::start(), you will have ambiguity error when trying to call the member function using unqalified namelookup from an object of C.
class A {
public:
virtual void start() { std::cout << "From A\n"; }
};
class B {
public:
void start() { std::cout << "From B\n"; }
};
class C: public A, private B {
};
int main(){
A* a = new C();
a->start(); //Ok, calls A::start()
C* c = new C();
c->start(); //Error, ambiguous
}
To fix that, you will have to use the qualified name such as:
C* c = new C();
c->A::start(); //Ok, calls A::start()
Now, doing a using B::start() in class C simply declares the start() to refer to B::start() whenever such name is used from an object of C
class A {
public:
virtual void start() { std::cout << "From A\n"; }
};
class B {
public:
void start() { std::cout << "From B\n"; }
};
class C: public A, private B {
public:
using B::start();
};
int main(){
A* a = new C();
a->start(); //Ok, calls A::start()
C* c = new C();
c->start(); //Ok, calls B::start()
}
using B::start makes the function void B::start() visible in C, it does not override it. To call make all the above unqualified member function call, to call B::start(), you should override the member function in C, and make it call B::start()
class A {
public:
virtual void start() { std::cout << "From A\n"; }
};
class B {
public:
void start() { std::cout << "From B\n"; }
};
class C: public A, private B {
public:
void start() override { B::start(); }
};
int main(){
A* a = new C();
a->start(); //Ok, calls C::start() which in turn calls B::start()
// ^^^^^^^^^^^^^^^^ - by virtual dispatch
C* c = new C();
c->start(); //Ok, calls C::start() which in turn calls B::start()
}
This is the simplified code:
class a
{
public:
void func( void )
{
//Want to call this
}
int avar;
};
class b : public a
{
public:
void func( void )
{
}
};
class c : public a
{
public:
void func( void )
{
}
};
class d : public b, public c
{
public:
void d1()
{
//b::a::avar;
//c::a::avar;
//b::a::func();
//c::a::func();
}
};
How do you properly qualify a call to access the members of both instances of the subclass a, the things I've tried leads to a 'a is an ambiguous base of d' error. Same question if the hierarchy was one more class deep or if a class template was involved. I'm not looking for a virtual base.
You can call the immediate base class functions using the explicit calls.
void d1()
{
b::func();
c::func();
}
You can call a::func from b::func similarly.
class b : public a
{
public:
void func( void )
{
a::func();
}
};
If you also want to access the member a::var and call a::func directly from d::d1, you can use:
void d1()
{
b* bPtr = this;
bPtr->avar; // Access the avar from the b side of the inheritance.
bPtr->a::func(); // Call a::func() from the b side of the inheritance
c* cPtr = this;
cPtr->avar; // Access the avar from the c side of the inheritance.
cPtr->a::func(); // Call a::func() from the c side of the inheritance
}