2

I have the problem of class functions making changes on different copies of a vector rather than the one saved in an instance of the corresponding object.

Description of the Main function: This is the main function. It first creates an object Menno of class Mats, which is initialized with its constructor and has a private vector of type int named F full of values -1. It then is used to create an object of class Calculator named Calli. The object Menno is saved in a private object variable of type Mats named Matrices in Calli. Finally, Matrices is returned by the getMatrices() function of Calli and printF() is carried out on this object variable, which changes values in F and is supposed to change F for all time.

Problem: As can be seen after executing the program, the changes made by printF() and setf() do not get saved in the object variable Matrices. This leads me to think that the initialization of F in the constructor works well, but the functions then use other copies of this vector rather than the saved one.

Background: As a Java Coder, I was advised to use pointers for most cases, but I still can't understand why this code doesn't work as intended. I recently investigated C++ as a programming language, went through thenewbostons video guide and printed out syntax lists but they don't help me here. Any explanation is appreciated!

// main function
#include "Calculator.h"
#include "Mats.h"
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int N = 4;
    Mats Menno(N);
    Calculator Calli(Menno);
    Calli.getMatrices().printF();
    Calli.getMatrices().setf(2,1);
    Calli.getMatrices().printF();
}

// Calculator header
#ifndef CALCULATOR_H
#define CALCULATOR_H
#include "Mats.h"
#include <vector>

class Calculator
{
    public:
        Calculator(Mats M);
        Mats getMatrices();
    protected:

    private:
        Mats Matrices;
};

#endif // CALCULATOR_H

// Calculator cpp
#include "Calculator.h"
#include "Mats.h"
#include <iostream>
#include <vector>
using namespace std;

Calculator::Calculator(Mats M)
: Matrices(M)
{
}

Mats Calculator::getMatrices(){
    return Matrices;
}

// Mats header
#ifndef MATS_H
#define MATS_H
#include "Calculator.h"
#include <vector>

class Mats
{
    public:
        Mats(int N);
        int getf(int i);
        void setf(int i, int fh);
        std::vector<int> getF();
        void printF();
    protected:

    private:
        std::vector<int> F;
};

#endif // MATS_H

// Mats cpp
#include "Calculator.h"
#include "Mats.h"
#include <iostream>
#include <vector>
using namespace std;

Mats::Mats(int N)
{
    std::vector<int> Fh;
    F = Fh;
    F.resize(N);
    for (int i = 0;i<N;i++){
        F[i] = -1;
    }
}

int Mats::getf(int i){
    return F[i];
}

void Mats::setf(int i, int fh){
    F[i] = fh;
}

std::vector<int> Mats::getF(){
    return F;
}

void Mats::printF(){
    F[1] = 300;
    cout << "F: " << endl;
    for (int i = 0; i<F.size(); i++) {
        cout << F[i] << " ";
    }
    cout << endl;
    F[1] = 200;
}
EE-Student
  • 85
  • 1
  • 10
  • 1
    What do you actually want (think) to achieve with these statements: `std::vector Fh; F = Fh;` in the `Mats` constructor? – πάντα ῥεῖ Aug 29 '16 at 21:55
  • 1
    _"... I was advised to use pointers for most cases ..."_ That's quite bad advice, don't use pointers in c++, unless you're absolutely sure you need them and what are you doing with these. – πάντα ῥεῖ Aug 29 '16 at 21:59
  • I didn't know how to initialize the private class member in an other way, without using the copy Fh. How would you do it? – EE-Student Aug 30 '16 at 18:22
  • That statement is actually a NOP. Use the member initializer list to initialize class member variables: https://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor – πάντα ῥεῖ Aug 30 '16 at 18:24
  • I don't want to initialize 'F' with the input 'int N' but set up a vector that is of length `N` (and fill it with -1). I am not aware of syntax that does this in another way. – EE-Student Aug 31 '16 at 18:16
  • See the [2nd constructor form here](http://en.cppreference.com/w/cpp/container/vector/vector) and use it as `Mats::Mats(int N) : F(N,-1) { // ...`. As mentioned `F = Fh;` is actually a NOP. – πάντα ῥεῖ Aug 31 '16 at 18:19

1 Answers1

3

Because

 Mats getMatrices();

returns a copy of the class member. Change it to return it by reference:

 Mats &getMatrices();

Note that returning a class member by reference has certain ramifications that you need to understand. You will find all the details in your favorite C++ book.

What happened here is that your self-described background in Java is getting in the way. C++ classes work fundamentally different than Java's classes. You need to forget everything you know about classes, as you know them in Java, and focus on learning how C++ classes work, from the basics.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • Also there are more flaws it seems. Don't try to be FGITW. – πάντα ῥεῖ Aug 29 '16 at 21:56
  • 1
    Certainly, but that wasn't the question that was asked. – Sam Varshavchik Aug 29 '16 at 21:56
  • @SamVarshavchik You've seen a question there? – πάντα ῥεῖ Aug 29 '16 at 22:00
  • 1
    Yes: "C++: Why do these functions use different copies of the vector?" That was the question that was apparently asked. And I answered it. – Sam Varshavchik Aug 29 '16 at 22:01
  • Why are people down-voting a correctly answered question? How does that make sense? – Galik Aug 29 '16 at 22:09
  • This is the correct answer and allowed my code to work as intended. However, your arguments indicate that there might be better approaches. How would you work with private class members that you need to manipulate on a frequent basis as given in the example? – EE-Student Aug 30 '16 at 18:19
  • Generally, if something is a private class member, it should be accessed only within the class, internally. After all, what's the point of a private member if anyone can get it just for asking. You should analyze what needs to be done to your private class members, write methods to do that, then invoke them when needed. – Sam Varshavchik Aug 30 '16 at 22:58
  • This means I should write the manipulation methods in the class where the private class member is initialized rather than in the private class members class. So in this example I should create the `setf()` method in the Calculator class rather than in the Mats class. Is this really so much different than it is done now? Atm I do not simply take the private class member and manipulate it but rather call `getMatrices()` to explicitly make sure I get the current class member. – EE-Student Aug 31 '16 at 18:13
  • "accessed" is not the same thing as "implemented". You would have a public class method that does nothing but invoke Matrices.setf(), and you would call that directly. – Sam Varshavchik Aug 31 '16 at 18:41
  • Alright: One shouldnt write functions that directly return references to private members of other classes. If that is a good rule of thumb, I can live with that. Thx. – EE-Student Aug 31 '16 at 20:51