eel 0 Newbie Poster

Currently writing a program for an OOP course on encapsulation. The program is required to instantiate only one object in main, but then instantiate multiple objects, within the first object, to perform calculations on arrays (Values)held within each object.

I have been taught that I should ensure that objects are responsible for performing calculations on their own data. But..

I am currently using an approach of overloading the subscript operator, in order to perform the add() function and assign the result equal to obj1 of class foo.

My question is: As obj1 is a member of class foo and the function add() is a member of class bar is this breaking the encapsulation rule of modifying another objects private members? Even if that object, obj1 is a private member of the class bar ?

 class foo      
       {
       public:
            foo(double* = 0, unsigned long = 0, bool = false);      
            ~foo(); 

            double& operator[] (unsigned int Index) { return Values[Index]; }               
            const double& operator[] (unsigned int Index) const { return Values[Index]; }   

        private:
            double* Values;
        };

        class bar       
        {
        public:
            bar(double* = 0);       
            ~bar(); 
             void add();

        private:
            double* Values;
            foo obj1;
            foo obj2;
        };

        void bar::add()
        {
            obj1[1] = obj2[1] * Values[1]; 
        }

        int main()
        {
            bar obj3;
            obj3.add;
        }

Dani AI

Generated

— Short answer: no, this is not inherently breaking encapsulation. Calling obj1's operator[] is using foo's public API. Encapsulation protects the class internals from direct access; if foo intentionally exposes a non-const operator[] that returns a double&, other code (including bar) is allowed to modify those elements via that public interface. The important design question is whether foo should expose a writable element-access API at all.

If the goal for the assignment is "each object is responsible for its own data", avoid exposing writable internals and instead give foo operations that maintain its invariants. For example, provide a controlled member that updates an element or that applies an operation using data from another foo:

class Foo {
public:
    Foo(size_t n = 0) : values(n) {}
    double get(size_t i) const { return values.at(i); }
    void set(size_t i, double v) { values.at(i) = v; }
    void multiplyInto(size_t i, const Foo& other, double scale) {
        set(i, other.get(i) * scale);
    }
private:
    std::vector<double> values;
};

A few practical points that tie back to your snippet: using raw double* requires you to implement the rule of three/five (copy ctor, copy assignment, destructor) or else you risk shallow-copy bugs. Prefer std::vector<double> or smart pointers for safer ownership semantics (std::vector, std::unique_ptr). Also check bounds (use at() or asserts) and ensure add() is actually invoked (use obj3.add();).

If modification should be restricted to only bar, the language offers friend but that weakens encapsulation; a better pattern is to give foo focused operations so callers express intent (e.g., foo.updateFrom(...)) rather than reaching inside foo via mutable element access.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.