0

I'm writing a C++ program where I have two derived objects from a base class, say, Derived_1 & Derived_2.

During processing, the first object adjusts the base data member (just simulating that using the Derived_1's default constructor here). What I'd like to do is then read that data from the Derived_1 object and use it during Derived_2's constructor to initialize that same member in Derived_2.

// -std=c++14
#include <iostream>

class Base {
 public:
  int data(void) { return data_; }

 protected:
  int data_{0};
};

class Derived_1 : public Base {
 public:
  Derived_1(void) { this->data_ = 42; }
};

class Derived_2 : public Base {
 public:
   // Derived_2(const Derived_1& a1) { this->data_ = a1.data_; }
};

int main() {
  Derived_1 a1;
  std::cout << "Derived_1 data: " << a1.data() << '\n';

  // Derived_2 a2 = a1;
  // std::cout << "Derived_2 data: " << a2.data() << '\n';
}

If the constructor in Derived_2 is uncommented, this error occurs:

In constructor ‘Derived_2::Derived_2(const Derived_1&)’:
error: ‘int Base::data_’ is protected within this context
Derived_2(const Derived_1& a1) { this->data_ = a1.data_; }
                                                  ^~~~~

I've looked through a number of related questions here on SO trying to find a solution, (for example) Access a derived private member function from a base class pointer to a derived object and Why can I access a derived private member function via a base class pointer to a derived object? but I'm currently having real difficulty spotting the answer if I've seen it. Probably just my inexperience.

Thanks for helping clear this up for me.

alarmed
  • 15
  • 3

3 Answers3

2

Yes, it is possible, by making Derived_2 a friend of Derived_1:

class Derived_1 : public Base {
    //This says that Derived_2 is a friend, which means that Derived_2
    //can access every member in Derived_1
    friend class Derived_2;
public:
    Derived_1(void) { this->data_ = 42; }
};

So now you can do this:

class Derived_2 : public Base {
public:
     Derived_2(const Derived_1& a1)
     { 
         //Legal, Derived_2 is a friend of Derived_1, so it can access the
         //protected member 'data_'
         this->data_ = a1.data_; 
     }
};

Note that now, Derived_2 can modify every data member of Derived_1, not just data_

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
  • Thanks Rakete1111, that's the solution. I had the instinct that **friend** might be the answer, but my attempts were clumsy and failed to work. I appreciate the nice comments in your answer as well! – alarmed Jun 16 '16 at 17:01
1

The first error is that data_ declared in the base class is not accessible to the derived classes for usage. To fix this, you need to include this is your derived class:

using Base::data_;

Now, what OOP recommends is that every object has well defined methods associated to it, and no variable is directly accessible. You can either do:

class Derived_2 : public Base {
 public:
   Derived_2(const int& a1) { this->data_ = a1; }
};

and use it like this:

Derived_2 a2(a1.data());

Or you may declare Derived_2 as a friend of Derived_1, just as @Rakete1111 mentioned in his answer:

class Derived_1 : public Base {
//This says that Derived_2 is a friend, which means that Derived_2
//can access every member in Derived_1
friend class Derived_2;
public:
    Derived_1(void) { this->data_ = 42; }
};

However, if you do this, all the variable in Derived_1 will be directly accessible to Derived_2.

EDIT 1(as requested): The usage of the class:

Version 1:

class Derived_1 : public Base {
 using Base::data_;
 public:
  Derived_1(void) { this->data_ = 42; }
};

class Derived_2 : public Base {
 using Base::data_; 
 public:
    Derived_2(const Derived_1& a1) { this->data_ = a1.data(); }
};

Version 2:

//Declaration of Derived_2 here for Derived_1 
//to know that a class with such a name exists
class Derived_2 : public Base;

class Derived_1 : public Base {
 using Base::data_;
 friend class Derived_2;
 public:
  Derived_1(void) { this->data_ = 42; }
};

class Derived_2 : public Base {
 using Base::data_; 
 public:
    Derived_2(const Derived_1& a1) { this->data_ = a1.data_; }
};
Sahil Arora
  • 875
  • 2
  • 8
  • 27
  • thank you for the answer. You mentioned _To fix this, you need to include `using Base::data_;` i[n] your derived class_ and I played around with it but was unable to make a difference. As before, it was probably just a clumsy mistake on my part due to inexperience. Is it possible you could edit your answer to demonstrate exactly how to use it in both derived classes please? Also, thank you especially for the tip on good OOP usage. In my usage code `Derived_2 a2 = a1;` seemed to convey my intent more directly than `Derived_2 a2(a1.data());` but yea, good advice! – alarmed Jun 16 '16 at 18:36
  • @Sahil_Arora thanks for the clarifications Sahil, I appreciate it! – alarmed Jun 16 '16 at 20:36
0

Derived classes have access only to protected members of their own base class sub object. They don't have access to other classes' bases protected members, even if that base is the same type as its own.

Possible solutions:

  • Declare Base::data_ public.
  • Or declare Derived_2 as a friend of Derived_1.
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thank you user2079303. One thing I specifically _didn't_ want to do is make the data public in my base class. And yes, **friend** turned out to be the answer. – alarmed Jun 16 '16 at 17:03