简体   繁体   中英

c++ derived base class Friend function accessing private on Parent?

Please consider the scenario below:

    class A 
    { 
     friend void B::Itemfunction();
     private:
     int number;
     int size;
     public:
     Randomfunction();
    }

    class B : public A
    {
     private:
     string Random;
     public:
     void Itemfunction();
     void CheckLog();

    }

Would it be possible for an object made in Itemfunction of type A to access the private data members of obj? Such as:

    void B::Itemfunction(){
    A obj;
    //Possible to do...
    obj.number = 2;
    }

I understand that the derived class B can access all the public parts of A, but if I wanted just one function (Itemfunction) to access the private parts would this be the correct way of doing it? I just want to see if my understanding is correct.

Cheers

In your code, where you implement Itemfunction , you are creating a new, completely unrelated object of type A locally. In inheritance, your B object has an internal subobject of type A . You can access the fields of A directly within B . However, you can't access private members. Your friendship trick will not work; you cannot declare a method of B a friend until you see B s definition, but B can't be defined until A is defined, and as you can see we're going in circles. What you can do instead is to make that member protected:

class A 
{ 
  protected:
  int number;
  private:
  int size;
  public:
  Randomfunction();
}

void B::Itemfunction() {
  number = 2;
}

No, it's not possible. You cannot friend a class member function for a class that isn't yet completely declared.

The only way in that case (since class B needs a completely declared class A to inherit), is to forward declare class B; and friend the whole class:

#include <iostream>
#include <string>

    class B;

    class A 
    { 
     // friend void B::Itemfunction();
     friend class B;
     private:
     int number;
     int size;
     public:
     void Randomfunction();
    };

    class B : public A
    {
     private:
     std::string Random;
     public:
     void Itemfunction();
     void CheckLog();

    };

int main()
{   
}

Live Demo

This has a chicken and egg problem. Both B must be fully defined for A to see B::Itemfunction .

class A
{
    friend void B::Itemfunction(); <-- Itemfunction does not exist yet
private:
    int number;
    int size;
public:
    int Randomfunction();
};

class B: public A
{
private:
    std::string Random;
public:
    void Itemfunction();
    void CheckLog();

};

Swapping the order won't work either because B needs A to be defined to inherit from A .

class B: public A <-- A does not exist yet
{
private:
    std::string Random;
public:
    void Itemfunction();
    void CheckLog();

};

class A
{
    friend void B::Itemfunction();
private:
    int number;
    int size;
public:
    int Randomfunction();
};

Solution 1 is forward define class B so the compiler knows that B exists, even if it knows nothing about it, and then friend the whole class, because A only knows B exists. OP's friend relationship is maintained.

class B; <-- forward definition of B
class A
{
    friend class B; <-- friending all of B, not just the function 
private:
    int number;
    int size;
public:
    int Randomfunction();
};

class B: public A
{
private:
    std::string Random;
public:
    void Itemfunction();
    void CheckLog();

};

BUT! All of B now has complete access to all of A . If A wants to keep size or any other members hidden and under it's control, tough. B can call all of A 's functions and change all of A 's member variables. B can totally pown A .

This also doesn't scale to other subclasses. B can see all of A , but C and D cannot.

So say you have a less trivial example where A cannot allow anyone to mess with the value of size . Maybe it's the capacity of an internal array, and changing size will result in A running past the end of allocated memory. The reason doesn't matter much here; for the sake of this example no one but A is allowed to change size .

This leads us to solution 2: protected access and accessor functions.

class A
{
protected: <-- all inheritors can access members in this block. No one else can
    int number;
private: <-- only A can access members in this block
    int size;
public:
    int Randomfunction();
    int getSize() <-- accessor function to provide read-only access to size
    {
        return size;
    }
};

class B: public A
{
private:
    std::string Random;
public:
    void Itemfunction(); <-- can do anything to number and read size
    void CheckLog(); <-- so can this

};

class C: public A
{
private:
    std::string member;
public:
    void doStuff(); <-- and this
    void DoOtherStuff(); <-- and this

};

B and C can access A::number and can use A::getSize to see the value of size . number can be changed by B and C , but size cannot. If you are worried about the cost of calling a function to read size , don't be. When the compiler is done with A::getSize , you won't even know it's there. It probably isn't.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM