0

I have a question about how to access private data members from another c++ class in a program I am writing. Up front, my question is: how can I access a private data member from outside of that class? All the code that I mention should be listed below, although much of the code for longint.cpp has not been implemented.

I have a class called "Deque" that represents a double ended queue. This double ended queue is made using linked nodes that I call "DequeNode". Each "DequeNode" has the private data members of a next and prev pointer as well as a variable to store a value/item. I have tested the deque.cpp and deque.h files with a driver I wrote and they are working as intended.

I want to make a class called LongInt, that presents an integer. A LongInt is supposed to represent an integer value that cannot be stored in an int variable. A LongInt has three private data members, a Deque object called digits, a bool value to determine if the value being stored in a LongInt is negative or positive, and a function to remove extra 0's at the front of the LongInt object.

I am having trouble writing an output function for the LongInt class. The output function for LongInt should print out all the values of all the nodes of its Deque object. My question is: how am I be able to access the Deque object called "digits" from the output function located in longint.cpp? Specifically, the operator<< function.

Below is the code for the files: deque.h, deque.cpp, longint.h, and longint.cpp.

deque.h:

#ifndef DEQUE_H
#define DEQUE_H
#include <iostream>

using namespace std;

template <class Object>
class Deque {
 public:
  Deque( );                                   // the constructor
  Deque( const Deque &rhs );                  // the copy constructor
  ~Deque( );                                  // the destructor

  bool isEmpty() const;                      // checks if a deque is empty.
  int size() const;                          // retrieves # deque nodes
  const Object &getFront() const;            // retrieve the front node
  const Object &getBack() const;             // retrieve the tail node

  void clear();                              // clean up all deque entries.
  void addFront( const Object &obj );         // add a new node to the front
  void addBack( const Object &obj );          // add a new node to the tail
  Object removeFront( );                      // remove the front node
  Object removeBack( );                       // remove the tail node

  const Deque &operator=( const Deque &rhs ); // assignment

 private:
  struct DequeNode {                          // a deque node
    Object item;
    DequeNode *next;
    DequeNode *prev;
  };
  DequeNode *front;
  DequeNode *back;
};

#include "deque.cpp"
#endif

deque.cpp:

template <class Object>
Deque<Object>::Deque() {                          // the constructor
  front = back = NULL;
}

template <class Object>
Deque<Object>::Deque(const Deque &rhs) {         // the copy constructor
  front = back = NULL;
  *this = rhs;
}

template <class Object>
Deque<Object>::~Deque() {                         // the destructor
  clear();
}

template <class Object>
bool Deque<Object>::isEmpty() const {             // check if a deque is empty
  return front == NULL;
}

template <class Object>
int Deque<Object>::size() const {                 // retrieves # deque nodes
  int i = 0;
  for ( DequeNode *ptr = front; ptr != NULL; ptr = ptr->next ) // traverse que
    ++i;

  return i;
}

template <class Object>
const Object &Deque<Object>::getFront() const {   // retrieve the front node
  if (isEmpty())
    throw "empty queue";
  return front->item;
}

template <class Object>
const Object &Deque<Object>::getBack() const {    // retrieve the tail node
  if (isEmpty())
    throw "empty queue";
  return back->item;
}

template <class Object>
void Deque<Object>::clear() {          // clean up all entries.
  while (!isEmpty())                 // dequeue till the queue gets empty.
    removeFront();
}
// add a new node to front
template <class Object>
void Deque<Object>::addFront(const Object &obj){

  DequeNode *new_node = new DequeNode;

  new_node->prev = NULL;
  new_node->next = front;
  new_node->item = obj;

//Checking for the edge case where we have no nodes
  if (front == NULL){  //If we have no nodes, both front and back get set to the only node.
    back = new_node;
    front = new_node;
  }
  else{ //Else, everything else is handled by this
    front->prev = new_node;
    front = new_node;
  }
}

// add a new node to tail
template <class Object>
void Deque<Object>::addBack(const Object &obj){

  DequeNode *new_node = new DequeNode;
  
  new_node->prev = back;
  new_node->next = NULL;
  new_node->item = obj;
  
//Checking for the edge case where we have no nodes
  if (back==NULL){ //If we have no nodes, both front and back get set to the only node.
    front = new_node;
    back = new_node;
  }
  else{ //Else, everything else is handled by this
    back->next = new_node;
    back = new_node;
  }
}

template <class Object>
Object Deque<Object>::removeFront(){  //remove the front node

  DequeNode *pos = front; //create a pointer to keep track of node to be deleted

  //Need to find a way to access the item being help at the location of front.
  Object removedItem = pos->item;

  if(front == back){ //Case for when there is only a single node left in the Queue.
    front = NULL;
    back = NULL;
  }
  else{ //All other cases should fall into this else statement
    front->next->prev = NULL;
    //front->next = NULL;
    front = front->next;
  }

  delete pos;

  return removedItem;
}

template <class Object>
Object Deque<Object>::removeBack(){   // remove the tail node

  DequeNode *pos = back; //create a pointer to keep track of node to be deleted

  //Need to find a way to access the item being help at the location of front.
  Object removedItem = pos->item;

  if(front==back){
    front = NULL;
    back = NULL;
  }
  else{
    back->prev->next = NULL;
    back = back->prev;
  }

  delete pos;
  return removedItem;
}

template <class Object>
const Deque<Object> &Deque<Object>::operator=(const Deque &rhs) { // assign
  if (this != &rhs) { // avoid self assignment
    clear();
    for (DequeNode *rptr = rhs.front; rptr != NULL; rptr = rptr->next)
      addBack(rptr->item);
  }
  return *this;
}

longint.h:

#ifndef LONGINT_H
#define LONGINT_H
#include <iostream>
#include "deque.h"

using namespace std;

class LongInt {
  friend istream &operator>>(istream &in, LongInt &rhs);
  friend ostream &operator<<(ostream &out, const LongInt &rhs);
 public:
  // Constructors
  LongInt(const string str); 
  LongInt(const LongInt &rhs);
  LongInt();

  // Destructor
  ~LongInt();

  // Arithmetic binary operators
  LongInt operator+(const LongInt &rhs) const;
  LongInt operator-(const LongInt &rhs) const;

  // assignment operators
  const LongInt &operator=(const LongInt &rhs);

  // Logical binary operators
  bool operator< (const LongInt & rhs) const;
  bool operator<=(const LongInt & rhs) const;
  bool operator> (const LongInt & rhs) const;
  bool operator>=(const LongInt & rhs) const;
  bool operator==(const LongInt & rhs) const;
  bool operator!=(const LongInt & rhs) const;

 private:
  Deque<char> digits;
  bool negative;
  void remove0s();
};

#endif

longint.cpp:

#include "longint.h"

//istream &operator>>(istream &in, LongInt &rhs){
  //return in;
//}

ostream &operator<<(ostream &out, const LongInt &rhs){
  cout << << endl;
  return out;
}




//Constructors
//LongInt::LongInt(const string str)
//LongInt::LongInt(const LongInt &rhs)

LongInt::LongInt(){
  digits.addBack(0);
  negative = false;
}

// Destructor
LongInt::~LongInt(){

  
}

// Arithmetic binary operators
//LongInt operator+(const LongInt &rhs) const;
//LongInt operator-(const LongInt &rhs) const;

// assignment operators
//const LongInt &operator=(const LongInt &rhs);

// Logical binary operators
//bool operator< (const LongInt & rhs) const;
//bool operator<=(const LongInt & rhs) const;
//bool operator> (const LongInt & rhs) const;
//bool operator>=(const LongInt & rhs) const;
//bool operator==(const LongInt & rhs) const;
//bool operator!=(const LongInt & rhs) const;


  • 4
    You should add public methods that give you the access you need. – john Dec 04 '20 at 08:22
  • 1
    You're not *supposed* to access `private` members outside the class. Alternatives (1) Use `protected` or `public` instead. (2) Write a member function to return the member (`const`?). (3) use a `friend`. (4) Circumvent `private` by writing a template specialisation with that member as the payload - access checks are not made. – Bathsheba Dec 04 '20 at 08:23
  • Most [decent books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282), tutorials or classes should have mentioned that output and input operator (`operator<<` and `operator>>`) are typically declared as `friend` of the class they output from or input to. But since you have already done that, then it should already work. If it doesn't work, then you need to be more specific about the problems you have. – Some programmer dude Dec 04 '20 at 08:23
  • 1
    It seems you want a way to iterate through the deque. So you should define a custom iterator that does this. This can be used in your LongInt class, but will be useful generally. Defining a new iterator is a fairly advanced topic but you should find some examples with an internet search – john Dec 04 '20 at 08:23
  • You already see that `operator<<` for `longint` is a friend function, so it has access to the internals of `longint`. That's the adviced approach. Don't expose your privates. – JHBonarius Dec 04 '20 at 08:25
  • 1
    @JHBonarius I think the problem here is that longint needs access to deque. Access it doesn't currently have because deque does not define an iterator. – john Dec 04 '20 at 08:26
  • Please take some time to read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). Then [edit] your question to give us more details about the problems you have what you want to do. – Some programmer dude Dec 04 '20 at 08:27
  • Only member functions of a class or a `friend` can access `private` members of a class. If you have something that is neither a member function nor a `friend` needing to access `private` members of a class, then your design is broken. Usually your class needs to provide an accessible (e.g. `public`) member function that, in turn, accesses the `private` member, or access it via a `friend`. And providing a `public` member that allows direct (unfettered) access to a `private` member is poor form - which completely negates any benefit of having `private` members. – Peter Dec 04 '20 at 08:40

0 Answers0