0

In the below program i have used two classes , and i am trying to relate the with aggregation, i have declare class A as private in class B, and with the help of constructor i am initizing base address of class A object to private member of class B object that is (A object). i am trying to pass the class A values to class B usng parametrized constructor, but i am getting garbage values like,

#include <iostream>
using namespace std;

void create (B * &obj2, int siz)
{
    std::cout << obj2[0].get_nn ();     //this will run fine
    for (int i = 0; i < siz; i++)
        obj2[i] = B (10, "pranjal");    //this will also run fine

    std::cout << obj2[0].get_nn ();
}
// same line printing again, this will not give output
// *************************************** 

void display ()
{
    std::cout << object.get_data () << object.get_stringdata ();
}

// giving garbage values
// why is it happening
// *********************************program
// ************************************** enter code here
// Online C++ compiler to run C++ program online

class A {
    int rool;
    string name;
  public:
    A () { };
    A (int a, string name);
    int get_data () {
        return rool;
    }
    string get_stringdata () {
        return this->name;
    }
};

A::A (int a, string name)
{
    this->rool = a;
    this->name = name;
}

void getdetails (A * obj)
{
    for (int i = 0; i < 3; i++)
        obj[i] = A (20, "pranjal");
}

class B {

    int bbb;
    string name;
    A object;
  public:
    B () {};
    B (A s) {
        object = s;
    }
    string get_nn () {
        return object.get_stringdata ();
    }
    B (int a, string b);

    void display () {
        std::cout << object.get_data () << object.get_stringdata ();
    }
};

void dis (B * obj2)
{
    for (int i = 0; i < 2; i++) {
        obj2[i].display ();
    }
}

void create (B * &obj2, int siz)
{
    std::cout << obj2[0].get_nn ();
    for (int i = 0; i < siz; i++)
        obj2[i] = B (10, "pranjal");

    std::cout << obj2[0].get_nn () << "sd";
}

B::B (int a, string b)
{
    bbb = a;
    name = b;
}

int main ()
{
    A *obj = new A[3];
    getdetails (obj);
    
    B *obj2 = new B[3];
    
    for (int i = 0; i < 3; i++) {
        obj2[i] = B (obj[i]);
    }

    create (obj2, 3);
    dis (obj2);
    obj2->display ();

    return 0;
}
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
pranjal
  • 3
  • 3
  • 1
    Your garbage values appear to be code. Is this correct or a cut and paste mistake? – user4581301 May 05 '21 at 06:21
  • 1
    In `create`, I don't think `delete[] obj2;` is a good idea. It seems counter productive. – user4581301 May 05 '21 at 06:25
  • ohh sorry i was just trying the changes in program, if icomment that delete[] obj2, then too i am getting garbage value – pranjal May 05 '21 at 06:38
  • pranjal sd 846122816 846122816 846122816 ai am getting this output, instead it should print pranjal , plz help – pranjal May 05 '21 at 06:42
  • Please review and [edit] your question to remove the comments from the code (or make them proper comments). See also our [formatting help](https://stackoverflow.com/help/formatting). – Lukas-T May 05 '21 at 06:50
  • 1
    When this assignment takes place `obj2[i]=B(obj[i]);` the values are indeterminate. – David C. Rankin May 05 '21 at 06:51
  • this is working fine actually, but second parameterized constructor is giving problem, by assiggning values to obj2[i]=B(10,"pranjal"); my A object variable data, which i assiged to obj2[j] is gettting vanished and giving garbage, plz suggest me what do i do? – pranjal May 05 '21 at 06:55
  • Side note: https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice (this actually applies for *all* namespaces...). – Aconcagua May 05 '21 at 07:02
  • Side note 2: You should get used to use constructor's initialiser list (not to be confused with `std::initializer_list`), it should look like `A::A(int a, string name) : rool(a), name(name) { }` (analogously for those of B), and your default constructor leaves `rool` uninitialised. Be aware that there are types that *only* can be initialised that way (references, `const` members, non-assignable types, ...). – Aconcagua May 05 '21 at 07:05
  • I changed the it accordingly you told but still not working – pranjal May 05 '21 at 07:17
  • Side note 3: No need for reference to pointer as parameter for `create` function: You get one indirection by the pointer already, and you do not intend to modify the pointer that is *passed* to the function. Thus: `void create(B* obj, size_t size)` – the correct type to specify sizes is `size_t`, by the way... – Aconcagua May 05 '21 at 07:21
  • yeah i did that way also but no effect :( – pranjal May 05 '21 at 07:24
  • @pranjal Side notes, i. e. unrelated to actual problem ;) – Aconcagua May 05 '21 at 07:39

2 Answers2

0
void create(B *&obj2,int siz)
{
    std::cout<<obj2[0].get_nn();      //this will run fine
    for(int i=0;i<siz;i++)
        obj2[i]=B(10,"pranjal");
    std::cout<<obj2[0].get_nn(); // same line printing again, this will not give output
}

Of course it won't: B(int, std::string) does not call a constructor of A explicitly, so A's default constructor is called. This implicitly calls name's default constructor, too, which will create an empty string.

For a similar reason you get garbage values: Your default constructor does not assign a value to rool, thus leaves it uninitialised; it will remain at the value that was there in memory before, which ever it was, which is what you consider 'garbage'.

This occurs because with obj2[i] = B(10,"pranjal") a new object is created and then copied into the target object (with optimisations, can be created directly in place, but obviously you cannot rely on).

Fix your constructor of A to assign a value to rool and the problem should go away. You might chose a non-zero value to have a more clearly visible effect:

A() : rool(1977) { }

Alternatively you can provide provide a default value to rool (requires C++11):

int rool = 1977;

That can be convenient especially if you have a larger number of constructors.

In general: You should not leave primitive types of any of your objects uninitialised to avoid similar problems.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
0

In create, you fully replace the previous B objects with brand new ones using the 2 parameters constructor... which just leaves the A object member default initialized.

What could be done to fix?

  1. Pass the parameters of B to A ctor:

     B::B (int a, string b): object(a, b)
     {
         bbb = a;
         name = b;
     }
    

    That way you initialize the A object member with the same parameters as its parent

  2. Reset the A object member to its previous value:

     void create (B * &obj2, int siz)
     {
         std::cout << obj2[0].get_nn ();     //this will run fine
         for (int i = 0; i < siz; i++) {
             A old = obj2[i].object;
             obj2[i] = B (10, "pranjal");    //this will also run fine
             obj2[i].object = old;
         }
         std::cout << obj2[0].get_nn ();
     }
    

    But as it requires accesses to private members, create should be declared friend in B class:

     class B {
         ...
         friend void create (B * &obj2, int siz);
     };
    
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252