Aidan
Aidan

Reputation: 37

How to access private variables from another class?

I'm working on a project in OpenGL, and I have it working in its most basic form. Now, I need to make it so that my "get" matrices for rotation and orbit are in my Box.cpp file, my speed variables are private, and that I have set functions for those speed variables.

I need to access those variables in main, but since they're private, I cannot obviously.

Can someone point me in the right direction?

main.cpp:

#include "vgl.h"
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
#include "Box.h"
#include "Camera.h"
#include "VertexBufferData.h"
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

using namespace std;
using namespace glm;

#define SPACEBAR_KEY 32
#define ESCAPE_KEY 033

Camera* camera;
vector<Box * > gameObjects;
bool keyDown[255];

void CheckKeyboard(){

    if (keyDown['a'])
        camera->RotateLeft();
    if (keyDown['d'])
        camera->RotateRight();
    if (keyDown['w'])
        camera->MoveForward();
    if (keyDown['s'])
        camera->MoveBackWard();
    if (keyDown['e'])
        camera->StrafeRight();
    if (keyDown['q'])
        camera->StrafeLeft();
}

void closeApp()
{
    delete camera;
    for (auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
        delete (*it);
    }
}


void keyboard(unsigned char key, int x, int y)
{
    switch (key) 
    {
        case ESCAPE_KEY:  // ASCII Escape Key Code
            closeApp();
            exit(EXIT_SUCCESS);
            break;
        default:
            keyDown[key] = true;
    }

    glutPostRedisplay();
}

void keyboardUp(unsigned char key, int x, int y)
{
    keyDown[key] = false;
}

void mouseWheel(int button, int direction, int x, int y)
{

    if (button == 16)
        camera->ResetFOV();
    else if (direction > 0)
        camera->ZoomIn();
    else
        camera->ZoomOut();
}

void mouseMovement(int x, int y)
{
    static bool warp = true;

    if (warp)
    {
        if (x>glutGet(GLUT_WINDOW_WIDTH) / 2)
            camera->RotateRight();
        else if (x<glutGet(GLUT_WINDOW_WIDTH) / 2)
            camera->RotateLeft();

        if (y>glutGet(GLUT_WINDOW_HEIGHT) / 2)
            camera->RotateUp();
        else if (y<glutGet(GLUT_WINDOW_HEIGHT) / 2)
            camera->RotateDown();

        glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
        warp = false;
    }
    else
        warp = true;
}

void timer(int value)
{
    glutPostRedisplay();
    glutTimerFunc(25, timer, 0);
}

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    CheckKeyboard();
    camera->Update();
    for (auto it = gameObjects.begin(); it != gameObjects.end(); ++it) {
        (*it)->shaderProgram->bindShader();
        glm::mat4 MVP = camera->ProjectionMatrix *  camera->ViewMatrix * (*it)->getModelMatrix();
        (*it)->shaderProgram->sendUniform4x4("MVP", glm::value_ptr(MVP));
        (*it)->Draw();
    }
    glutSwapBuffers();
}

void init()
{
    int i = 0;

    camera = new Camera();
    memset(keyDown, false, sizeof(keyDown));

    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
    glutWarpPointer(glutGet(GLUT_WINDOW_WIDTH) / 2, glutGet(GLUT_WINDOW_HEIGHT) / 2);
    glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_CULL_FACE);

    VertexBufferData vertexBufferData = VertexBufferData("Data\\Models\\Objects.xml");

    gameObjects.push_back(new Box(vertexBufferData, glm::vec3(0.0f, 0.0f, 0.0f), "Data\\Shaders\\Vertex.shader", "Data\\Shaders\\Fragment.shader"));

    gameObjects.push_back(new Box(vertexBufferData, glm::vec3(4.0f, 0.0f, 0.0f), "Data\\Shaders\\Vertex.shader", "Data\\Shaders\\Fragment.shader"));

    gameObjects[1]->rotationSpeed = 5.0f;
    gameObjects[0]->rotationSpeed = 2.5f;
    gameObjects[1]->orbitSpeed = 1.0f;
    //gameObjects[1]->setRotation(45.0f, vec3(0.0f, 0.0f, 1.0f));
    //gameObjects[0]->setScaleMatrix(vec3(2, 2, 2));
    //gameObjects[1]->setOrbitMatrix(vec3(2.0f, 0.0f, 0.0f), 45.0f, 1, 365, 0);
}



int main(int argc, char** argv)
{
    glutInit(&argc, argv);

    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH);
    glutInitWindowSize(1024, 768);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutCreateWindow("Satterwhite_Project_3");


    if (glewInit())
    {
        cerr << "Unable to init glew" << endl;
        exit(EXIT_FAILURE);
    }

    init();
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutKeyboardUpFunc(keyboardUp);
    glutPassiveMotionFunc(mouseMovement);
    glutMouseWheelFunc(mouseWheel);
    glutTimerFunc(25, timer, 0);
    glutMainLoop();
    return 0;
}

Box.cpp:

#include "Box.h"

Box::Box(VertexBufferData &vbd,  vec3 initialPosition,const string vertexShader, const string fragmentShader):GameObject(vertexShader, fragmentShader)
{   
    degreesRotated = 0.0f;
    rotationSpeed = 0.0f;
    orbitSpeed = 0.0f;
    Position=initialPosition;
    vertexBufferData =vbd;

    RotationMatrix=mat4(1.0f);
    OrbitMatrix = mat4(1.0f);
    ScaleMatrix=mat4(1.0f);
    TranslationMatrix =translate(glm::mat4(1.0f), Position);

    if (!shaderProgram->initialize())
    {
        std::cerr << "Could not initialize the shaders" << std::endl;
    }

    shaderProgram->bindShader();

    glGenVertexArrays(1, &VAO);
    glBindVertexArray(VAO);

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertexBufferData.verticiesSize, &vertexBufferData.verticies[0], GL_STATIC_DRAW);

    glGenBuffers(1, &fragmentBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
    glBufferData(GL_ARRAY_BUFFER, vertexBufferData.colorSize, &vertexBufferData.colors[0], GL_STATIC_DRAW);

    shaderProgram->linkProgram();
}
void Box::setRotation(float degrees, vec3 axis)
{
    RotationMatrix = rotate(RotationMatrix, degrees, axis);
}

void Box::setScaleMatrix(vec3 scale)
{
    ScaleMatrix = glm::scale(mat4(1.0f), scale);
}

void Box::setOrbitMatrix(float degrees, vec3 axis)
{
    OrbitMatrix = rotate(OrbitMatrix, degrees, axis);
}

void Box::Draw()
{
    shaderProgram->bindShader();

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));

    glBindBuffer(GL_ARRAY_BUFFER, fragmentBuffer);
    glVertexAttribPointer(1, 3, GL_FLOAT,GL_FALSE, 0, BUFFER_OFFSET(0));    

    glDrawArrays(GL_TRIANGLES, 0, vertexBufferData.verticies.size());

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
}

Box.h:

#pragma once
#include "GameObject.h"

class Box :  public GameObject
{

private:
    mat4 ModelMatrix;
    mat4 RotationMatrix;
    mat4 OrbitMatrix;
    mat4 TranslationMatrix;
    mat4 ScaleMatrix;
public:
    float rotationSpeed, orbitSpeed, degreesRotated;
    void Draw();
    virtual ObjectType getType() const { return BOX; }

    mat4 getModelMatrix() {return getOrbitMatrix()*TranslationMatrix*getRotationMatrix()*ScaleMatrix;}
    mat4 getRotationMatrix()
    { 
        setRotation(rotationSpeed, vec3(0.0f, 0.0f, 1.0f));
        return RotationMatrix;
    }
    mat4 getTranslationMatrix() {return TranslationMatrix;}
    mat4 getOrbitMatrix()
    {
        setOrbitMatrix(orbitSpeed, vec3(0.0f, 0.0f, 1.0f));
        return OrbitMatrix;
    }
    mat4 getScaleMatrix() {return ScaleMatrix;}
    void setRotation(float degrees, vec3 axis);
    void setScaleMatrix(vec3 scale);
    void setOrbitMatrix(float degrees, vec3 axis);

    Box(VertexBufferData &vertexBufferData, vec3 initialPosition, const string vertexShader, const string fragmentShader);

    vec3 Position;
};

Upvotes: 1

Views: 25501

Answers (2)

Spektre
Spektre

Reputation: 51835

In case you do not want to change the protected class you can do this:

class c0    // this is some class with protected stuff and you do not want or can to change it in any way
    {
public:
    c0(){};
    ~c0(){};
protected:
    int x;
    };
class c1:c0 // this is class just to access c0 stuff without changing its source code
    {
public:
    c1(){};
    ~c1(){};
    int get_x() { return x; }
    void set_x(int new_x) { x=new_x; }
    };
void test()
    {
    c0 a;
    c1 *b=(c1*)(&a);    // access a as c1 type
    b->set_x(1);        // access protected stuff
    }

I often use this to access VCL class stuff without changing it in any way (for example to avoid unnecessary memory transfers and more).

Beware variables and stuff is usually protected for a reason and by changing it in wrong way you may cause unforseen problems like access violation ,memory leaks etc ... so be careful what are you changing with what and at what time.

But this does not work for private members so for those you need to tamper with the source code to add geters/setters or friends as @Raindrop7 answer suggest.

Upvotes: 1

Raindrop7
Raindrop7

Reputation: 3911

  • if you want to access private and protected members from another class then declare that class you want to access your target class's private and protected members as a "friend class".

  • if you want to access private and protected members from main or any other function rather than from a class then declare that function to be a friend of your class like ostream insertion operator "<<" and istream extraction operator ">>" when you overload them in your class to print and input your member data.

declaring a class or a function to be friend of your class is like making a new friend in real life whom you trust so you let him/her access your secrets and private stuff so he/she can help you achieve what you find so tough to do yourself but friendship is neither commutative nor associative: "being him/her your friend doesn't mean being you his/her friend because he/she still maybe doesn't trust you thus doesn't declare you to be his/her friend", friend of your father is not your friend.

  • the overhead of using friendship is undermining data hiding and encapsulation principles. so the law of thumb is to use it cautiously.

  • if you want everyone can access your private/protected members then use structs their members are by default public scoped. or declare your member data in your class public scoped and this is a very bad design.

in this example I'll show you how to access private data from another class and from another function (in this case main function):

#include <iostream>
#include <string>
using namespace std;


class Foo; // forward declaration
class Bar; // forward declaration

class Foo
{
    public:
        Foo() : MyData(100){}

    private:
        int MyData;
        friend class Bar; // any access scope is ok. Bar will have full access to Foo
        friend int main(); // main now can access private members
};

class Bar // friend of Foo but Foo is not my Friend so it can't access mine
{
    Foo fooObj;

    public:
        Bar(){}
        void PrintFoo()const;
};

void Bar::PrintFoo()const
{
    cout << fooObj.MyData << endl; // accessing private member data of class Foo from Bar
}


int main()
{
    Foo theFoo;
    Bar theBar;
    theBar.PrintFoo();

    cout << theFoo.MyData << endl; // correct! accessing private members of foo from main because main is friend of Foo.

    return 0;
}

Upvotes: 3

Related Questions