pstatix
pstatix

Reputation: 3848

Accessing private members via reference accessor

What is the appropriate way to access private members of a referenced class instance? For example, accessing the initialNumberOfColumns from an instance of Cookie? Then have that value be used in another classes member function, such at Game::Game() after the reference accessor has retrieved the member of the Cookie class.

first.h:

class Cookie {
    public:
        Cookie();
        ~Cookie();
        void takeABite (int column, int row);
        int getNumberOfRows();
        int getNumberOfRows(int colNum);
        int getNumberOfColumns();
        int getNumberOfColumns(int rowNum);
        void display (std::ostream& output);

    private:
        int initialNumberOfRows;
        int numberOfRows;
        int numberOfColumns
        int* cookie;
};

second.h:

class Game {
    public:
        Game();
        bool gameEnded();
        bool biteIsLegal (int column, int row);
        Cookie& getCookie();

    private:
        Cookie cookie;
};

second.cpp is where I am having difficult. I know I need to use Cookie& Game::getCookie() but I am not sure how to return the private members of the Cookie class such that they can be accessed in the member function Game() below.:

Cookie& Game::getCookie() {
    return //not sure how to access;
}

Game::Game() {
    initialNumberOfRows = numberOfRows = 4 + rand() % (MAXROWS - 4);
    numberOfColumns = numberOfRows;

    while (numberOfColumns == numberOfRows) {
        numberOfColumns = 4 + rand() % (MAXROWS - 4);
    }

    cout << "The cookie has " << numberOfRows << " rows of " 
         << numberOfColumns << " columns" << endl;

    for (int row = 0; row < numberOfRows; ++row) {
        cookie[row] = numberOfColumns;
    }
}

Upvotes: 0

Views: 554

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597036

The Game class has a cookie member. That is what the Game::getCookie() method should return:

Cookie& Game::getCookie() {
    return cookie;
}

Now, inside of the Game constructor, you have direct access to the cookie member, so you don't need to use getCookie() to access it. And the Cookie class has public methods for reading most of the values you are trying to use, but it DOES NOT provide any access to set those member values, or any access to its private initialNumberOfRows member at all.

The things you are trying to do in the Game constructor should be done in the Cookie constructor instead:

Cookie::Cookie() {
    initialNumberOfRows = numberOfRows = 4 + rand() % (MAXROWS - 4);

    numberOfColumns = numberOfRows;
    while (numberOfColumns == numberOfRows) {
        numberOfColumns = 4 + rand() % (MAXROWS - 4);
    }

    cookie = new int[numberofRows];

    for (int row = 0; row < numberOfRows; ++row) {
        cookie[row] = numberOfColumns;
    }
}

Then the Game constructor can log the values as needed:

Game::Game() {
    cout << "The cookie has " << cookie.getNumberOfRows() << " rows of " 
         << cookie.getNumberOfColumns() << " columns" << endl;
}

Now, that being said, the Cookie class is violating the Rule of Three. It needs to implement a copy constructor and copy assignment operator to ensure the integrity of its int *cookie field:

class Cookie {
public:
    Cookie();
    Cookie(const Cookie &src);
    ~Cookie();

    Cookie& operator=(const Cookie &rhs);
    void swap(Cookie &other);

    ...

private:
    int initialNumberOfRows;
    int numberOfRows;
    int numberOfColumns
    int* cookie;
};

#include <algorithm>

Cookie::Cookie() {
    initialNumberOfRows = numberOfRows = 4 + rand() % (MAXROWS - 4);

    numberOfColumns = numberOfRows;
    while (numberOfColumns == numberOfRows) {
        numberOfColumns = 4 + rand() % (MAXROWS - 4);
    }

    cookie = new int[numberOfRows];
    std::fill(cookie, cookie + numberOfRows, numberOfColumns);
}

Cookie::Cookie(const Cookie &src) :
    initialNumberOfRows(src.initialNumberOfRows),
    numberOfRows(src.numberOfRows),
    numberOfColumns(src.numberOfColumns),
    cookie(new int[numberOfRows])
{
    std::copy(src.cookie, src.cookie + numberOfRows, cookie);
}

Cookie::~Cookie()
{
    delete[] cookie;
}

Cookie& Cookie::operator=(const Cookie &rhs)
{
    if (this != &rhs)
        Cookie(rhs).swap(*this);
    return *this;
}

void Cookie::swap(Cookie &other)
{
    std::swap(initialNumberOfRows, other.initialNumberOfRows);
    std::swap(numberOfRows, other.numberOfRows);
    std::swap(numberOfColumns, other.numberOfColumns);
    std::swap(cookie, other.cookie);
}

Otherwise, change the int *cookie member to a std::vector instead, and let the compiler and STL handle the hard work of memory management for you:

#include <vector>

class Cookie {
public:
    Cookie();

    ...

private:
    int initialNumberOfRows;
    int numberOfRows;
    int numberOfColumns
    std::vector<int> cookie;
};

Cookie::Cookie() {
    initialNumberOfRows = numberOfRows = 4 + rand() % (MAXROWS - 4);

    numberOfColumns = numberOfRows;
    while (numberOfColumns == numberOfRows) {
        numberOfColumns = 4 + rand() % (MAXROWS - 4);
    }

    cookie.resize(numberOfRows);
    std::fill(cookie.begin(), cookie.end(), numberOfColumns);
}

Upvotes: 1

Related Questions