Using (::) in a class's member function definition - c++

I was testing out classes and I made this class
class Point
{
private:
int x,y;
public:
void setit(int new_x,int new_y);
void set_x(int new_x);
void set_y(int new_y);
int get_x();
int get_y();
};
now I went ahead and wrote the function definitions for all the public functions but,
There is something that puzzled me when i was writing the void set(int new_x,int new_y);
function definition
void Point::setit(int new_x, int new_y){
Point::set_x(new_x);
Point::set_y(new_y);
}
void Point::setit(int new_x, int new_y){
set_x(new_x);
set_y(new_y);
}
I noticed that the two previous function definitions have the exact same effect.
I thought that without the :: operator it wouldn't work because it would search for the functions outside the class, since I no longer signify they are in the Point class
Can anyone explain why they both have the same effect??
Thank You.

:: is the scope resolution operator; it can tell the compiler exactly where to look for a name.
The Point::set_x is simply an extended syntax for calling a member function.
set_x(new_x);
Is short for
this->set_x(new_x);
And
Point::set_x(new_x);
Is equivalent for
this->Point::set_x(new_x);
It allows you to select which function to call when a class hides a function in a parent class. For instance:
struct A {
void f();
};
struct B : public A {
void f(); // Hides A::f
};
B binst;
binst.f(); // Calls B::f
binst.A::f(); // Calls A::f
One thing you can do with this syntax is call the member function of a parent class from the overridden virtual function of a base class, allowing you to use the "default implementation" provided by the base class. You can also do it from outside the class, similar to hidden functions:
struct A {
virtual void f() {
cout << "A::f" << endl;
}
};
struct B : public A {
virtual void f() override {
cout << "B::f" << endl;
A::f(); // if we just did f(), it would call B::f, and we
// would get infinite recursion
}
};
B b;
b.f(); // prints B::f A::f
b.A::f(); // prints B::f

Inside a class member function, all the class member names are in scope, so set_x is found.
Moreover, the class name itself is visible inside class member functions (it is said to be injected), and thus Point::set_x is also found. But for the same reason, Point::Point::set_x and Point::Point::Point::Point::set_x are also ways to name the function.

:: is a scope resolution operator. To access the function in the scope of the Point class' namespace you can use the :: operator, but because the function setit(int new_x, int new_y) is already in the same scope as set_x and set_y, there is no requirement to define the overall scope of those functions. The program will call the functions with matching symbols to set_x and set_y in the most local scope.

Related

Derived class calling parent class's method that calls an overriden virtual method calls the wrong method

First of all, sorry for the confusing title. I have no idea how to word this properly.
The problem is not really a problem, but rather something that I don't know how to implement.
Here is the code:
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
void foo()
{
std::cout << "Child's foo" << std::endl;
}
};
int main()
{
Child c;
c.bar();
return 0;
}
When the code above runs, it prints outChild's foo.
However the same code, BUT with the child classes foo definition beingvoid foo(bool def = true)Prints out Parent's foo.
Is there anyway to call the child's version of foo instead of the parent's one if the definitions missmatch?
Unfortunately not, if you want to add extra parameters, even default ones, you can create an overloaded function explicitly, which behaves similar in most cases to the caller.
#include <iostream>
class Parent
{
public:
virtual void foo()
{
std::cout << "Parent's foo" << std::endl;
}
void bar()
{
foo();
}
};
class Child : public Parent
{
public:
virtual void foo(bool def) // virtual if another subclass needs to override
{
std::cout << "Child's foo def = " << def << std::endl;
}
virtual void foo()override //override and virtual optional here
{
foo(true);
}
};
int main()
{
Child c;
c.bar();
c.foo();
c.foo(true);
return 0;
}
This is purely a function of when a function is overridden in C++.
In C++, function overriding is done according to the "signature" of member functions:
unqualified name
exact parameters list in the declaration (excluding implicit this)
qualification of the this implicit parameter
Obviously, by definition, the type of the this parameter cannot match exactly, as by definition the type must be a pointer to a derived class.
[Note about cv-qualification on parameters:
The parameters in the declaration as seen by caller must be exactly the same, that is after removal of meaningless cv-qualifiers on object copies: these are cv-qualifiers on local variables inside the function body, and that's only meaningful in a function definition.
void f(const int i); // takes an int by value; const is meaningless
void f(int i); // redeclaration of the same function
// redeclaration of the same function yet again
void f(const int ci) { // const is meaningful here
ci = 1; // error
}
--end note]
However the same code, BUT with the child classes foo definition
being void foo(bool def = true) Prints out Parent's foo.
Because there is no match of the parameters lists: an empty parameter list is only matched by an empty parameter list.
You need to replace the default argument with two overloaded functions here, with no forwarding to the other:
void foo(bool def); // new function signature
void foo() { // overrides Parent's member
foo(true);
}
With long complex a parameters list, it's easy to change a type and create a new function signature instead of overriding a base class virtual function; it's also easy to get the capitalisation wrong or spelling wrong (think English vs. US spelling). In general, getting the name of a function wrong (or any other name: of a type, of a template, of a variable...) causes a compilation error because that name with the small spelling change wasn't declared. But with a raw declaration of a member with the intent of overriding a base class declaration, there is no hint that you tried to do that and the compiler will not warn you (it might warn for hiding a base class declaration, but this is different). Explicitly marking a declaration intended to be an override with the virtual keyword doesn't help, introducing a new virtual function isn't the intent.
That was the sad state of affairs after the first version of the C++ standard was formalized. Now it's different.
If you want to be sure that you are indeed overriding a base class declaration, you can now use the override keyword:
class Child : public Parent
{
public:
void foo(bool def);
void foo() override {
foo(true);
}
};

Function definition in Inheritance

When publicly inheriting a class, why can't I define a function of the base class using name of derived class if the public members of base class are inherited by that derived class?
Example:
#include <iostream>
using namespace std;
class one{
int a;
public:
void get(int);
void show();
};
class two:public one
{
int b;
public:
void getb(int);
void dis();
};
void one::get(int x) //if i write void two::get(int x) here it gives error
{
a = x;
}
void one::show() //same goes for this function why can't i define it as `void two::show()`?
{
cout << a << endl;
}
int main()
{
two ob;
int x;
cin >> x;
ob.get( x );
ob.show();
}
So if if all public member functions of class one are inherited by class two, why can't I define functions of class one using name of class two ?
Why ?
In the class definition, you say that two inherits from one. So it will have the following public members:
void get(int); publicly inherited from one
void show(); publicly inherited from one
void getb(int); own member
void dis(); own member
You can define only the own member functions of two, here two::getb(int) and two::dis(). But you can't define two::show() because it was defined in one and you did not tell the compiler that you wanted it.
Is there a way to do have a different version of the inherited functions ?
If you'd define the class as follows:
class two:public one
{
int b;
public:
void getb(int);
void dis();
void show(); //yes you can, but you'll have to define it
};
then you would have the following public members:
void get(int); publicly inherited from one
void one::show(); publicly inherited from one but hidden
void show(); own member
void getb(int); own member
void dis(); own member
you could define the following:
void two::show() //no problem !!
{
cout << "two's version" << endl;
}
You could even choose in main() which one you want to call:
ob.get( x ); // one::get(), because there's no two::get()
ob.show(); // by default two::show(), because ob is a two
ob.one::show(); // yes you can !!
Here an online demo
Want polymorphism ?
In all the code above, the function invoked depend on the type used to access the object:
one *pob = &ob; // a one pointer can point to a two object
pob->show(); // but this will invoke one::show()
If you'd prefer the right function be called depending on the real type of the object, and not the type assumed from the type declaration, you'd need to use virtual functions and override them:
class one{
... (the rest as before) ...
virtual void show();
};
class two:public one
{
... (the rest as before) ...
void show() override;
};
Then, whenever you invoke show(), the correct function will be called (online example), unless you specifically inkove a precisely specified version by using a fully qualified identifier.

How to call an abstract function with an abstract class

I want define a function in an abstract class which calls a abstract (virtual) function. But when I inherit from the abstract class this function is not inherited:
class A {
public:
virtual void f(int t) = 0;
void f() {
f(0);
}
};
class B : public A {
public:
void f(int t) override { }
// using A::f; // uncomment to fix the problem
};
int main() {
B b;
b.f(0); // works
b.f(); // error: no matching function for call to ‘B::f()’
}
Why doesn't this work? The workaround is to use using A::f, but why is A::f() not inherited?
It doesn't work because B does not have an f(), only an f(int).
If B did not have any function named f, then the superclass would be searched for a matching function, with overload resolution taking place. But because the subclass, B, does already have a function named f, the superclass is not searched, and the overload resolution happens in B.
This is what the using keyword is for, to make the superclass's f() a part of B's namespace. The answer here is, really, "that's because this is how C++ works".

Inheritance with two functions with different signatures hides the non-virtual function

Forgive the obscure title. It's likely a duplicate but I couldn't find the correct phrase.
Consider the following inheritance hierarchy.
class A
{
public:
virtual void Foo(int i) { printf("A::Foo(int i)\n"); }
void Foo(int a, int b) { Foo(a + b); }
};
class B : public A
{
public:
void Foo(int i) override { printf("B::Foo(int i)\n"); }
};
class C : public B
{
public:
void Bar() { Foo(1, 2); } //error C2660: function does not take two arguments
};
A has two methods named Foo with a different number of parameters. Only one of them is virtual.
B overrides the virtual method.
C tries to call the non-virtual method and encounters an error.
Calling the method as A::Foo(1, 2) does work fine.
Question:
Why can't the compiler deduce that the correct method is found on A?
It seems odd we would have to explicitly add A:: in a call such as:
C c;
c.A::Foo(1, 2);
Because the member function named Foo is found at the class scope of B, and then name lookup stops, so the Foo in class A is not visible, and won't be considered for overload resolution, even if the version in class A is more appropriate. It is name hiding.
You can use using to introduce them into the same scope, and make overload resolution work as you expect. Such as:
class C : public B
{
using A::Foo;
using B::Foo;
public:
void Bar() { Foo(1, 2); }
};
See Unqualified name lookup
LIVE

What are the rules for virtual function lookup?

#include <iostream>
class base
{
public:
virtual void print (int a)
{
std::cout << "a: " << a << " base\n";
}
virtual void print (int a, int b)
{
std::cout << "base\n";
}
};
class derived : public base
{
public:
virtual void print (double d)
{
std::cout << "derived\n";
}
};
int main ()
{
int i = 10;
double d = 10000.0;
base *b = new derived ();
b->print (i, i);
b->print (d);
return 0;
}
The output of this function is:
base
a: 10000 base
Why b->print (d) don't invoke the derived class implementation and
performs static cast on 'd' to provide a match with base class
implementation ?
What rule is applied here during virtual function lookup ?
derived::print does not override any member function in base. It is declared as having a single parameter of type double but the two virtual member functions named print in base are declared as having one and two parameters of type int.
When you use b->print(d), only member functions in base are considered during overload resolution, so only void base::print(int) and void base::print(int, int) are considered. void derived::print(double) can't be found because the compiler has no idea that b points to a derived object.
If derived were to override one of the two print functions declared as virtual member functions in base, then that override would be called at runtime.
(On a somewhat related note, derived::print hides the two base::print member functions, so if you were to try to use one of the base class print functions, e.g., derived().print(1, 1), it would fail. You would need to use a using declaration to make those member functions available during name lookup.)
Overload resolution happens at compile time. Overrides happen at run time.
Therefore, the overload resolution of b->print(d); happens first. This selects Base::print(int) because it's the only one-argument print.
At runtime, b points to a Derived object that has no override for Base::print(int). Therefore, Base::print(int) is still called.
Because double can be automatically converted to an int in the first definition it sees (in the base class)
See explicit keyword or this question