class instance (object) dot namespace double colon non static function

59 Views Asked by At
#include <iostream>
using namespace std;

namespace xyz {
    class Base {
    public:
        bool configure (double a) {
            cout << "Do nothing. a is currently equal to: " << a << endl;
            return true;
        }
        
        virtual bool update(float& a)=0;
   };  
}

class Child : public xyz::Base {
public:
    virtual bool update(float& a) {
        a = a+0.5;
        cout << "Updated" << endl;
        return false;
    }
};

int main() {
    cout << "Hello World" << endl;
    
    Child median;
    float a = 3.0;
    median.update(a);
    median.xyz::Base::configure(a);
    return 0;
}

I think I miss some C++ concept here.

I am totally lost how median.xyz::Base::configure(a); this line is even a thing. Which is a class instance (object) median dot a namespace:: xyz and then :: notation to the parent class Base that I have only used for static class methods (but configure (double a) is not even static...).

How can this be explained to even work/compile?

This is a simplified MWE from a robotics library that I modified so that it is more generic (https://github.com/ANYbotics/grid_map/blob/master/grid_map_filters/include/grid_map_filters/MedianFillFilter.hpp)

2

There are 2 best solutions below

2
NathanOliver On

What you are seeing here is explicitly calling the base class version of the function. For example if you had

namespace xyz {
    
    class Base {
    public:
        bool configure (double a) {
            cout << "Do nothing. a is currently equal to: " << a << endl;
            return true;
        }
        
        virtual bool update(float& a)=0;
   };  
}

class Child : public xyz::Base {
public:
    virtual bool update(float& a) {
        a = a+0.5;
        cout << "Updated" << endl;
        return false;
    }
    bool configure (double a) {
            cout << "In Child::configure. a is currently equal to: " << a << endl;
            return true;
        }
};

int main() {
    cout << "Hello World" << endl;
    
    Child median;
    float a = 3.0;
    median.update(a);
    median.configure(a);
    return 0;
}

then median.configure(a); will print In Child::configure. a is currently equal to: 3.5 as it is calling the Child version of the function. By using

median.xyz::Base::configure(a);

it will instead print Do nothing. a is currently equal to: 3.5 as it is now explicitly using the Base version of the function. You can see the output change in this live example.

0
463035818_is_not_an_ai On

The full name of Base is ::xyz::Base. The full name of its configure method is ::xyz::Base::configure. Usually you do not need or do not want to explicitly mention the fully qualified name.

For example when Child overrides a method from Base then you want the overiding method to be called. On the other hand, if, for any reason, you do want to call the method of the base class you can fully qualify the name.

Consider this slightly modified example:

#include <iostream>
using namespace std;

struct foo {
    virtual void a() { std::cout << "foo::a\n"; }
};
struct bar : foo {
    void a() { 
        foo::a();
        std::cout << "bar::a\n"; 
    }
};

int main() {
    bar b;
    b.a();
    b.foo::a();
}

Output is:

foo::a
bar::a
foo::a

Inside bar::a I had to call foo::a to call the method from the base class, because just a() would have been resolved to bar::a (and there would be infinite recursion). Also in main I can call the method from the base class by calling a.foo::a(). While the latter is not that typical, the first is a common way to call a function that would otherwise be hidden or not reachable via name resolution.