Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using-declaration for friend function

In C++11 it is possible to make a public member of a private base class accessible to the outside (public) with a using declaration. For example

class A {
private:
    int i = 2;
public:
    void f() { i = 3; }

    friend bool operator==(const A& l, const A& r) { return l.i == r.i; }
};

class B : private A {
public:
    using A::f;
};

int main() {
    B b, b2;
    b.f();
}

b.f() is possible because of the using A::f in the definition of B.

Is it possible write a similar declaration which would make the up-cast from B& to A& possible for the friend function operator==(A&, A&), so that b == b2 can be called in main()?

like image 441
tmlen Avatar asked Nov 29 '16 18:11

tmlen


People also ask

Where do I put my friend's class declaration?

Friends aren't in the class's scope, and they aren't called using the member-selection operators (. and ->) unless they're members of another class. A friend function is declared by the class that is granting access. The friend declaration can be placed anywhere in the class declaration.

Can we declare main function as friend?

main() can very well be a friend of any class. Just declare it as a friend inside the class like you do for other member functions.

Does friend need forward declaration?

Friend Functions For a free function, it is very straightforward and a forward declaration is not required. We can simply declare the friend as follows: The void Print(const Test& test) function has access to the private members of the Test class. For a member function, it's not as straightforward as the free function.


1 Answers

No, only B can internally cast itself to A, and it otherwise is not possible because from a client's perspective B is not an A but rather has an A

Even if you replaced your friend bool operator= with a member function equals:

class A {
private:
    int i = 2;
public:
    void f()  { i = 3; }

    bool equals(const A& r){return i == r.i;}
};

class B : private A {
public:
    using A::f;
    using A::equals; 
};

While this compiles, you cannot ever call b.equals(b2) because no implicit conversion is ever possible from a type of B to a type of A from the caller's perspective (due to private inheritance) .

You'll need to provide your own operator== or change your inheritance to public or protected. Here's an example where B declares its own friend bool operator==

class B : private A {
public:
    using A::f;
    friend bool operator==(const B& l, const B& r)
    {
        return (static_cast<A>(l) == static_cast<A>(r)) && true; 
        // "true" is a stand-in for some other condition
    }
};

Read more at isocpp


Edit: If you really want to play games, you will notice that I said no implicit conversion is ever possible, but some explicit conversions are. Because B does technically derive from A you can do pointer casting to make it work, but I don't recommend it:

class A {
private:
    int i = 2;
public:
    void f()  { i = 3; }

    bool equals(const A* r){return i == r->i;}
};

class B : private A {
public:
    using A::f;
    using A::equals;
};

int main() {
    B b, b2;
    b.f();
    (::A*)(&b)->equals((::A*)(&b2));  
}

Or you could use pointer casting's ugly cousin, reference casting, if you wish to keep the original operator== syntax

class A {
private:
    int i = 2;
public:
    void f()  { i = 3; }

    friend bool operator==(const A& l, const A& r) { return l.i == r.i; }
};

class B : private A {
public:
    using A::f;
};

int main() {
    B b, b2;
    b.f();
    ((::A&)(b)) == ((::A&)(b2));  
}

See §11.2 [class.access.base] for more

like image 193
AndyG Avatar answered Sep 29 '22 08:09

AndyG