Accessing overloaded method from a parent class - c++

I have stumbled upon this code, and I can't understand, why do I need to specify the class I want to call the method with one argument from? What's more interesting, if I remove the second overloaded method with two parameters, everything will work fine.
class A {
public:
virtual void foo(int a) const final {};
virtual void foo(int a, int b) const = 0;
};
class B : public A {
public:
void foo(int a, int b) const override {}
};
int main() {
B b;
b.A::foo(1); // Why do I need to specify A::foo??
// b.foo(1) -- won't compile
}

Because what b sees is the overloaded instance of foo(int a, int b), which preforms name hiding, therefore foo(int a, int b) makes foo(int a) invisible from b. If you want to make foo(int a), you should specify that it should look in class A, that's why you need A::

It is because when you override foo in B, the other overloads foo from base A are masked. It is a feature of language.

Related

Register/change method from other class in c++

I wonder what is the proper way to assign/override a method from that of another class. For example, here below classes A and B are not and should not be subclassed, but method "A.foo" is a prototype and should be assinged/set in the initialization of B. That is, "A.foo = B.bar_b" (or C or D etc). (The overall idea is to register a send method of servers (B) with a client (A).)
class A {
public:
virtual void foo(arg argA) {
// empty
};
};
class B {
public:
B(A a) {
a.foo = &B::bar_b;
}
void bar_b(arg argA) {
// do stuff B
};
};
A a;
B b(a);
a.foo(arg) // calls bar_b
It doesn't work that way. There are two ways to answer your question. The first is to use proper overriding:
class A {
public:
virtual void foo() {
// empty
};
};
class B : public A {
public:
void foo() override {
// do stuff B
};
};
B b;
A& b_ref = b;
b_ref.foo(); // calls B::foo
The other way is trying to interpret what you actually want to do. Perhaps you want to swap some implementation at runtime to select what A::foo is actually doing.
You need a B to call a method of the class B. Also B(A a) passes the A by value and the assignment in the constructor wont have any effect on the A you pass. Though, most importantly you cannot dynamically assign member functions. However, you can assign to member variables:
#include <functional>
struct A {
public:
void foo() {
do_foo();
};
std::function<void()> do_foo;
};
class B {
public:
B() = default;
B(A& a) {
a.do_foo = [](){B b; b.bar_b(); };
}
void bar_b() {};
};

Overload a virtual method in a derived class so it takes more parameters in C++

I have an abstract class A with the pure virtual method void foo(int a) = 0
Then I have several classes that inherit from A and all of them define the method foo. But I need one of them, B, to make it so foo takes an extra parameter, int b, so sort of an overload.
Then I would like to do this:
A *bInstance = new B();
bInstance -> foo(1, 2);
But I get an error telling me that foo is taking too many parameters.
Writing this, I realize it's kind of a weird thing to do so maybe you can't do this and it's good that you can't do it. But in case it is possible, please do tell me how I should go about it.
You can use the overloaded function of B only if the pointer to use is of type B.
See:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo(int a) = 0;
};
class B : public A
{
public:
virtual void foo(int a) override
{
}
void foo(int a, int b)
{
std::cout << a << "," << b;
}
};
int main(){
auto b = std::make_shared<B>();
b->foo(1, 2);
//to use a:
A* aPtr = b.get();
aPtr->foo(1);
return 0;
}
Although Bernd's answer is a possiblility, you must ask yourself what the effect of an overload is. E.g., think of the following.
std::unique_ptr<A> bAsA = std::make_unique<B>();
bAsA->foo(1, 2); // no worky.
bAsA->foo(1); // works, but what should it do?
It there's a different interface between A and B, I would suggest to add a layer of abstraction in form of a new base class (which I will call C).
So instead of
struct A {
// common
virtual void bar() {}
// class specific
virtual void foo(int) = 0;
};
struct B: public A {
// weird unused override which is still available
void foo(int) override {}
// class specific
void foo(int, int) {}
};
use
struct C {
// common
virtual void bar() {}
};
struct A: public C {
// class specific
virtual void foo(int) = 0;
};
struct B: public C {
// class specific
void foo(int, int) {}
};
You can fully achieve want you want using a default parameter:
class A
{
public:
virtual void foo(int a, int b = 0) = 0;
virtual ~A() = default;
};
class B : public A
{
public:
void foo(int a, int b) override { }
};
class C : public A
{
public:
void foo(int a, int b = 0) override { }
};
int main()
{
A* b = new B();
A* c = new C();
b->foo(1, 2);
c->foo(1);
}
You don't have to use this parameter in C::foo implementation (and any other derived classes) if you don't need to.

Acessing overloaded function from an Abstract Base class

I know this question has been asked before in some form. But I am still confused.
Suppose I have two classes.
class A{
public:
void foo(int a, int b);
protected:
virtual void foo(int a) = 0;
}
class B : public class A{
void foo(int a);
}
Now if I want to make the visibility of the non virtual function in class A public in class B .... how do I do that?? ... In other words currently I am able to call the non virtual function in this manner
B b;
b.A::foo(3, 5);
and I want to avoid this ^
and the solution of putting this
using A::foo;
in public B refers the virtual function in A .... not the non-virtual function ... so I think that is not the solution.
class A{
public:
void foo(int a, int b);
protected:
virtual void foo(int a) = 0;
};
class B : public A{
public:
using A::foo;
protected:
void foo(int a);
};
void f()
{
B b;
b.foo(1,2); // OK
b.foo(3); // error: ‘virtual void B::foo(int)’ is protected within this context
}
works as expcted. foo with two parameters is callable, foo with one not.

Calling function with two template parameters

I am having a problem calling a template function with two template arguments.
I have a class and the class accepts objects of two different types. I don't know the types yet, so I left them as template parameters. I then store the objects in wrapper classes. In the end I want to be able to call a templated function with two template arguments, that takes my two objects. But I am perplexed at how to do this.
Here is a stripped down version of the code to explain my problem.
template<typename A, typename B>
void someTemplateFunction(A a, B b);
class Problem
{
private:
class WrapperA
{
public:
virtual void doSomething() = 0;
};
template<typename A>
class ConcreteWrapperA : public wrapperA
{
private:
A a;
public:
ConcreteWrapperB(A b_) : a(a_) {}
virtual void doSomething();
};
class WrapperB
{
public:
virtual void doSomething() = 0;
};
template<typename B>
class ConcreteWrapperB : public wrapperB
{
private:
B b;
public:
ConcreteWrapperB(B b_) : b(b_) {}
virtual void doSomething();
};
WrapperA *a;
WrapperB *b;
public:
template<typename A>
void setA(A a)
{
a = new ConcreteWrapperA<A>(a);
}
template<typename B>
void setB(B b)
{
a = new ConcreteWrapperB<B>(b);
}
void call_someTemplateFunction(); // ??????? How do i do this?
};
The problem is that you've type-erased both types A and B separately, so there's nowhere in the translation of your code that both types A and B are known.
If you can write a single function template<typename A, typename B> void set(A, B) then you could capture the pair type <A, B> at that point.
Alternatively, would it be possible for someTemplateFunction to operate without knowing both types A and B at the same time?
This is an issue fundamental to the design of C++ as a single-pass, separate compilation language.
Suppose that your program has three compilation units; A.cpp calls setA with a range of types T[A], B.cpp calls setB with another range of types T[B], and C.cpp owns the Problem object and wants to call someTemplateFunction. Then there's no time during compilation when the compiler knows both the range of types in A.cpp and the range of types in B.cpp, so it can't instantiate someTemplateFunction with the appropriate cross-product T[A] x T[B].

Multiple inheritence, selecting which virtual function to call

I have the following code sample:
class A
{
public:
A(int a):AA(a) {};
int AA;
virtual int Test()
{
return AA;
};
};
class B
{
public:
B(int b):BB(b) {};
int BB;
virtual int Test()
{
return BB;
};
};
class C:public A, public B
{
public:
C(int a, int b, int c) :A(a),B(b),CC(c) {};
int CC;
};
int main()
{
A *a = new C(1,2,3);
B *b = new C(1,2,3);
C *c = new C(1,2,3);
int x = a->Test() ; // this is 1
int y = b->Test() ; // this is 2
// int z = c->Test() ; // this does not compile
return 0;
}
I was expecting the calls to a->Test() and b->Test() to be ambiguous too as the object a is a C and therefore inherits from A and B both of whom have identical Test() functions. However, they both call the implementation which corresponds to the delcared type rather than the type that the object actually is.
Can anyone explain why these calls are not ambiguous?
Does C++ always behave this way?
In fact,a C instance is both a full A instance and a full B instance (so holds a copy of A methods & B methods)
Since a is a A* , the compiler will use the A virtual table copy that is inside of the C instance
Since b is a B* , the compiler will use the B virtual table copy that is inside of the C
instance
you cannot use C* since the compiler will not now which Test() method of A or B you want to call (since the C class holds both A::Test & B::Test symbols)
if you implement a C::Test() method, then it will be called both instead of A::Test() & B::Test() since method is virtual for both A & B.
Because A does not know anything about the existence of C.
Consider a slightly different scenario:
foo.h
class A { public: virtual void Test() {} };
void myFunction(A *a);
foo.cpp
#include "foo.h"
void myFunction(A *a) {
a->Test();
}
You would expect this to compile, I guess? But what if I later independently inherited from A, should that affect whether this code compiles?