Suppose:
struct A {
virtual int foo(const A& a) const { return 1; }
};
struct B : A {
virtual int foo(const A& a) const { return 2; }
virtual int foo(const B& b) const { return 3; }
};
void testOverloadingBinding(const A& a,const B& b) {
cout << a.foo(b);
}
int main() {
testOverloadingBinding(B(),B());
}
It prints 2. I would assume it prints 3 since this binding is dynamic, and as far as I know overloading has static binding.
Can anyone please explain how the compiler decides which function to invoke here?
This:
virtual int foo(const B& b) const;
is not an override for this:
virtual int foo(const A& a) const;
Therefore it can never be called via a reference to an A.
virtual int foo(const B& b) const;
doesn't override anything, so compiler chooses first function. But, probably in future, we will have a dynamic type resolution, and in this case compiler will choose second function.
For more info, see http://www2.research.att.com/~bs/multimethods.pdf
There is simply no overload available to resolve to. The object you are calling foo on is of type A and in A only one function foo(const A&) exists. The dynamic dispatching yields the function in the base class. In C++ a member function is identified by its name and its arguments. Adding an overload in a base that does not exist in the parent will not enable dynamic dispatch onto it.
Related
In C++, suppose I have a member variable of type Bar, and I want to make sure only const methods are called on it. So then AFAIK I can declare it as a const Bar member variable like below:
class Foo
{
public:
Foo(const Bar& b) : bar(b) {}
void setBar(Bar& b) {
bar = b; // compiler complains here
}
private:
const Bar bar;
}
But I also want to be able to re-assign bar altogether. Is this possible to do without the compiler complaining?
The "trick" is to have your member data be a std::shared_ptr<const Bar> instead of const Bar; you can then re-assign the shared_ptr at will, but can't change Bar since the pointer is const.
#include <memory>
struct Bar final {};
struct Foo final
{
//Foo(const Bar& b) : bar(b) {}
Foo(const Bar& b) : pBar(std::make_shared<const Bar>(b)) {}
void setBar(const Bar& b) {
//bar = b; // compiler complains here
pBar = std::make_shared<const Bar>(b);
}
private:
//const Bar bar;
std::shared_ptr<const Bar> pBar;
};
Note that std::unique_ptr might be better than std::shared_ptr, but then you've got to add copy/assignment, assuming you want those. However, since it's a shared_ptr to constBar, it's not all that bad.
const members create more problems than they solve. If you want to make sure to only call const methods on bar but you want it not to be const (because you want to reassign it) then you can add another layer of encapsulation. For example:
struct Bar {
void doSomething() const {}
};
struct BarHolder {
BarHolder(const Bar& b) : bar(b) {}
const Bar& get() {return bar;}
void set(const Bar& b) { bar = b;}
private:
Bar bar;
};
class Foo {
public:
Foo(const Bar& b) : bar(b) {}
void doSomething() {
bar.get().doSomething(); // <- can only call const methods
}
void setBar(Bar& b) {
bar.set(b);
}
private:
BarHolder bar;
};
It didn't occur to me at first, but as mentioned in a comment, you similarly get "another layer of encapsulation" by using a std::unique_ptr<const Bar>, though then the object will be actually const.
If you want the Bar member variable to be re-assignable, then you don't want it to be const. This doesn't mean you can't call the const member functions on it; it just means that if a competing non-const overload exists, it will call the non-const one -- for example:
struct Bar {
// (1)
auto get_baz() -> Baz&;
// (2)
auto get_baz() const -> const Baz&;
};
Bar bar;
const Bar cbar;
auto& b1 = bar.get_baz(); // calls (1) because bar is not const
auto& b2 = cbar.get_baz(); // calls (2) because cbar is const
This issue does not happen if there are no non-const competing overloads:
struct Bar {
auto get_buzz() const -> const Buzz&;
};
Bar bar;
const Bar cbar;
// These both call the one get_buzz
auto& b1 = bar.get_buzz();
auto& b2 = cbar.get_buzz();
If you want to explicitly force the call to the const overload, you just need to make sure you call it from a const-qualified object or reference instead. This can be done easily with c++17's std::as_const
const Baz& b = std::as_const(bar).get_baz(); // calls (2)
If you don't have access to C++17, then you could also just form a const reference to Bar either by using a static_cast, or by using a temporary const reference, such as:
const Baz& b = static_cast<const Bar&>(bar).get_baz();
// or
const auto& const_bar = bar;
const Baz& b = const_bar.get_baz();
The first thing I'd point out is that your understanding of "const" methods is a bit off: a const method does not mean that it can modify const members, but that it can be called on a const instance of that class.
Eg if you have
class Foo {
public:
void method1() const { ... };
void method2() { ... };
}
and then a const instance of Foo as
const Foo foo1;
then you could call
foo1.method1()
becuase method1 is const, as is foo1; but you could not call method2, because foo1 is const, and method2 is not.
That said, what you are looking for is probably the "mutable" keyword on your member: usually a const method will not allow changing any members of that class (well, because the instance of that calss is const!); however, you can tag individual members of the class to be "mutable", which will allow const methods to change that member.
Eg, if you have
class Foo { public:
int a;
mutable int b;
void method() const { ... }
}
Then Foo::method() would be allowed to change 'a', but not 'b'.
Once you declare a member of a class as const, then only the constructor can set this member.
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.
Say i have this part of code:
#include<iostream>
using namespace std;
class A {
public:
virtual int f(const A& other) const { return 1; }
};
class B : public A {
public:
int f(const A& other) const { return 2; }
virtual int f(const B& other) const { return 3; }
};
void go(const A& a, const A& a1, const B& b) {
cout << a1.f(a) << endl; //Prints 2
cout << a1.f(a1) << endl; //Prints 2
cout << a1.f(b) << endl; //Prints 2
}
int main() {
go(A(), B(), B());
system("pause");
return 0;
}
I can understand why the first two will print 2. But I cannot understand why the last print is also 2. Why doesn't it prefers the overloaded function in B?
I already looked at this and this but I couldn't manage to understand from these.
int B::f(const B& other) const doesn't override int A::f(const A& other) const because the parameter type is not the same. Then it won't be called via calling f() on reference of the base class A.
If some member function vf is declared as virtual in a
class Base, and some class Derived, which is derived, directly or
indirectly, from Base, has a declaration for member function with the
same
name
parameter type list (but not the return type)
cv-qualifiers
ref-qualifiers
Then this function in the class Derived is also virtual (whether or
not the keyword virtual is used in its declaration) and overrides
Base::vf (whether or not the word override is used in its
declaration).
If you use override specifier (since C++11) compiler will generate the error.
class B : public A {
public:
int f(const A& other) const { return 2; }
virtual int f(const B& other) const override { return 3; }
};
Such as Clang:
source_file.cpp:10:17: error: 'f' marked 'override' but does not override any member functions
virtual int f(const B& other) const override { return 3; }
^
If you add an overload for it in the base class, you might get what you want. Note that a forward declaration of class B will be needed.
class B;
class A {
public:
virtual int f(const A& other) const { return 1; }
virtual int f(const B& other) const { return 1; }
};
LIVE
It's easy, really. You're calling f on an object with static type A. A has only one f, so there's only one entry in the vtable for that function. Overload resolution takes place compile-time. The overload will only be resolved if you call it on an object whose static type is B
The confusion comes in that your:
int f(const A& other) const { return 2; }
line is actually virtual also and is overriding your line:
virtual int f(const A& other) const { return 1; }
Meanwhile, the line:
virtual int f(const B& other) const { return 3; }
ends up being completely ignored because everything matches to the "return 1" line, then follows polymorphically up the chain to the "return 2" line. As the other poster said, the const B portion means it won't match the polymorphic method call.
As an aside: If you're getting a 2 on the first line, I'm suspicious of undesired stack behavior. I'd expect a 1. Perhaps try allocating like this:
A a1;
B b1, b2;
go(a1, b1, b2);
So I have a storage class that has a ton of basic functionality that is really useful as is. It has move constructors to allow return by value.
class A
{
public:
virtual ~A(){}
A(const A& a);
A(A&& a);
A& operator=(const A& rhs);
A& operator=(A&& rhs);
int foo();//example member function
//example function returning by value, elision and RHR make it efficient
static A Foo();
};
This is great because it allows who own A to be very well defined. If I start needed to have inherited classes that extend A, AND the return statement of a call function to have polymorphism, is the only "correct" way to use smart pointers? AKA
class B_interface : public A
{
public:
virtual ~B_interface(){}
virtual void FooBar() = 0;
};
class B : public B_interface
{
public:
virtual ~B(){}
B(const B& a);
B(B&& a);
B& operator=(const B& rhs);
B& operator=(B&& rhs);
virtual void FooBar() override;
static shared_ptr<B> idontlikeit();
}
I thought of a (probably bad) way to get around it: if, instead of inheritance, use composition: the class contains something akin to a impl ptr:
class B_interface
{
public:
virtual void FooBar() = 0;
};
class B : public A
{
shared_ptr<B_interface> impl_;//could use
public:
B(const A& a,shared_ptr<B_interface> interface)//or some smarter way to pass this in
: A(a)//call a's copy constructor
{
impl_.reset(interface);
}//this constructor thinks
void FooBar() { impl_->FooBar();}
virtual ~B(){}
B(const B& a);
B(B&& a);
B& operator=(const B& rhs);
B& operator=(B&& rhs);
static B ilikeitbetter();
}
So I like using the class better with that one, but making the class kinda stinks with that one...also, the B_interface might not make much sense outside B...Do you guys have any alternatives?
Yes, runtime polymorphism requires dynamic allocation and pointers. Derived classes can be (and usually are) of different size than base classes, so code expecting value semantics would not know how large a block to reserve for the value type.
In this specific case, consider returning a unique_ptr<Interface> if you don't expect the caller to require shared semantics. That way you don't force the caller to do reference counting if they don't need it. (The caller can always transfer ownership from the unique_ptr to a shared_ptr if they want shared semantics)
In the below program, the function 'f' in the base class A is hidden for the objects of derived class B. But when I call function f through const A *d which is pointing object of B, function f from the base class is getting invoked. If I remove const specifier for the pointer (i.e. A *d) function 'f' from derived class is called. My query how the constness is making a difference here ? Thanks for any help.
#include <iostream>
class A
{
public:
virtual void f(int n) { std::cout << "A::f\n"; }
virtual ~A() { }
void f(int n) const { std::cout << "A::f const\n"; }
};
class B
: public A
{
public:
void f(int n) { std::cout << "B::f\n"; }
void f(int n) const { std::cout << "B::f const\n"; }
};
int main()
{
const A a;
B b;
A &c = b;
const A *d = &b;
c.f(1);
d->f(1);
return 0;
}
Output (with const A *d):
B::f
A::f const
Output (with A* d)
B::f
B::f
The signature of the function to be called is determined on call site based on the static type of the pointer. The correct overrider of this signature is then chosen at runtime.
In other words, if you have this:
const A *d;
d->f(1);
then the f is searched for in const A. So it finds the non-virtual void f(int) const.
However, if you have this:
A *e;
e->f(1);
then the f is searched for in non-const A. So it finds virtual void f(int), which is then (at runtime) delegated to the final overrider void B::f(int).
EDIT
This follows from the rules on member function selection. When accessing through a const path (pointer or reference), only const member functions are applicable. When accessing through a non-const path, non-const functions are considered. Only if there is none is the pointer (or reference) implicitly converted to a pointer (or-reference) to const and then the const member functions are considered.