Praveen
Praveen

Reputation: 81

C++ member function as friend

I have 2 Classes Namely A and B with following independent declaration

class A {
private:
    std::vector<B> vec = {B("X","Y")};
public:
    A();
    void clear(std::vector<B>::size_type index);
};

class B {
private:
    std::string m_first;
    std::string m_second;
public:

    B() = default;
    B(std::string first, std::string second) : m_first(first), m_second(second) {}
    
    // I want the friend below - how to do it?
    friend void A::clear(std::vector<B>::size_type index);
};

I want to declare void A::clear(std::vector<B>::size_type index) to be friend of class B. Is it possible in C++? I cannot do forward declaration of B for A as A needs to see B's constructor with 2 arguments.

Upvotes: 4

Views: 232

Answers (2)

Peter
Peter

Reputation: 36637

You've set things up so the class A needs to be defined before B (so B can declare a member of A as a friend) but simultaneously B needs to be defined before A (so the vec member of A can be initialised using the constructor of B).

This is a circular dependency (definition of A must be before definition of B which must be before the definition of A - ad infinitum).

Declaring a member of a class as a friend is not possible unless that class has been previously defined.

You need to break that circular dependency - either by not having A::clear() as a friend of B, or by not initialising the vec member of A within the class definition (which means you then need to initialise vec solely in the constructor of A).

Alternatively, it is possible to declare A as friend of B without A being previously defined (i.e. a previous declaration of A is sufficient, without making it a definition). So an alternative may be to declare A as a friend of B rather than only A::clear().

This means that B must be defined before A. B can be defined without visibility of the definition of A.

Upvotes: 1

I'm 99% sure that your requirement to have A::clear as a friend of B is a case of too tight of a coupling. This is friendship misuse. Think of another way of doing it.

Please edit the question and provide the reason why you think you need that friendship. What is exactly the relationship between these classes, what's the use case? Convince us that there's a need for friendship, because I don't see it.

And the best I can tell the signature of B's constructor is wasteful in copying the arguments (by taking them by value). These arguments should be taken by const reference, unless you need a copy to modify within the method/constructor. I've fixed it below.

A needs to see B constructor with 2 arguments .

It doesn't! A doesn't. Only A's constructor does:

#pragma once
#include <string>
#include <vector>

class B;

class A {
private:
    std::vector<B> vec;
public:
    A();
    void clear(std::vector<B>::size_type index);
};

class B {
private:
    std::string m_first;
    std::string m_second;
public:

    B() = default;
    B(const std::string &first, const std::string &second) : 
        m_first(first),m_second(second)  {}
    friend void A::clear(std::vector<B>::size_type index);
};

inline A::A() : vec{ B("X", "Y") } {}

Another trick is to put A inside of B. But it's wholly unnecessary.

#pragma once
#include <string>
#include <vector>

class B {
private:
    std::string m_first;
    std::string m_second;
public:
    class A {
    private:
        std::vector<B> vec = {B("X","Y")};
    public:
        void clear(const std::vector<B>::size_type &index);
    };

    B() = default;
    B(const std::string &first, const std::string &second) : 
        m_first(first),m_second(second)  {}
    friend void A::clear(const std::vector<B>::size_type &index);
};

using A = B::A;

Upvotes: 1

Related Questions