-1

A.hh

#ifndef A_HH
#define A_HH

#include <iostream>
#include <string>

using namespace std;

class A {
private:
int size;
string name;

public:
A();
~A();
int Load(int, string);

int getSize();
string getName();

/* data */
};

#endif

A.cc:

#include "A.hh"


A::A() {

}


int A::Load(int _size, string _name) {
size = _size;
name = _name;
return 0;
}

int A::getSize() {
return size;
}

string A::getName() {
return name;
}

A::~A() {

}

B.hh:

#ifndef B_HH
#define B_HH

#include "A.hh"
#include <string>

class B {
private:
A* objectA;

public:
B();
B(A*);
~B();

A* getA();

/* data */
};
#endif

B.cc:

#include "B.hh"

B::B() {

}

B::B(A* obj) {
objectA = obj;
}

A* B::getA() {
return objectA;
}

B::~B() {

}

C.cc

#include "C.hh"

C::C() {

}


int C::doSomething() {
cout<<"size = "<<getA()->getSize()<<endl;
cout<<"name = "<<getA()->getName()<<endl;

return 0;
}


C::~C(){

}

C.hh

#ifndef C_HH
#define C_HH
#include "B.hh"


class C : public B {
public:
C();
~C();

int doSomething();
/* data */
};

#endif 

main.cc

#include "A.hh"
#include "B.hh"
#include "C.hh"

int main() {
A* objA = new A();
objA->Load(1, "Hello Drew Dormann :)");

B* objB = new B(objA);

C* objC = new C();
objC->doSomething();

return 0;
}

Why am I getting a segfault on doSomething()?

I'm using the child of B to handle the object parsed into B. Also I have to use B's child to handle A because this is part of something much bigger and this is the only way to simplify it.

I don't understand why this happens.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
Jack
  • 722
  • 3
  • 8
  • 24
  • 1
    your first and last line in main() are the problems. Maybe using new might fix it. – tp1 Aug 14 '15 at 21:43
  • 1
    *"the values of A are not parsed on B."* This must not be the real code if you can compile your code. – Drew Dormann Aug 14 '15 at 21:47
  • @tp1 Nope, it's there. I just forgot to add it in the description. Thanks for noticing it. – Jack Aug 14 '15 at 21:47
  • 1
    @Pavlos where is `Load` defined (not declared)? I haven't seen it. – Caninonos Aug 14 '15 at 21:49
  • @DrewDormann Yes, this is not the real code. But it's what i'm essentially trying to do. The real code is too big. I can't upload it. – Jack Aug 14 '15 at 21:49
  • @Caninonos It's defined in Class A. And also it works 100% that's why it's so mind boggling. – Jack Aug 14 '15 at 21:50
  • @Pavlos that's not what I ask, in your post we see: `int Load(int, string);` which is only the declaration, not the definition, can you post a compilable code (i.e. with the definition) which reproduces your problem? – Caninonos Aug 14 '15 at 21:52
  • @Caninonos Uploading on git now. – Jack Aug 14 '15 at 21:53
  • 4
    A [MCVE](http://stackoverflow.com/help/mcve) ***in this question*** is required to diagnose your problem. – Drew Dormann Aug 14 '15 at 21:55
  • By the info he has given us there is no problem with [it](http://cpp.sh/9r4u) – ChajusSaib Aug 14 '15 at 21:59
  • 2
    @DrewDormann second time today I've seen this user post a question that doesn't compile... – caps Aug 14 '15 at 22:00
  • @DrewDormann maybe this is the root of the problem and I would not like to share my code unless it's necessary? – Jack Aug 14 '15 at 22:02
  • 2
    You are not _supposed_ to share your real code. You are supposed to post a testcase. You have sort of half tried to do that here, but you forgot a few steps, namely _checking that the testcase actually builds_, let alone reproduces the problem. – Lightness Races in Orbit Aug 14 '15 at 22:03
  • @Pavlos You will need to create us a new example that the problem you describe actually occurs. Otherwise we cannot help. – ChajusSaib Aug 14 '15 at 22:04
  • @LightnessRacesinOrbit I'll keep that in mind. I'm using StackOverflow for only 2 weeks. – Jack Aug 14 '15 at 22:05
  • @ChajusSaib the info he gave us here does not compile, so I would say there is a problem with it in that regard. Once modified to compile, as you have done, if it does not reproduce his issue, then that is a further problem. – caps Aug 14 '15 at 22:05
  • @caps Yea but I mean editing the code with the info he has given us, it still does not reproduce the error. As he said "The Load() function in Class A successfully manages to store the values entered by the user to the private values." – ChajusSaib Aug 14 '15 at 22:10
  • 1
    I'm creating the compilable now. – Jack Aug 14 '15 at 22:14
  • 1
    @Pavlos: When you signed up 24 days ago, you were shown the Tour. Should have read it! – Lightness Races in Orbit Aug 14 '15 at 23:48
  • 1
    Man this is far too much code. You still haven't read the instructions. http://stackoverflow.com/help/mcve – Lightness Races in Orbit Aug 14 '15 at 23:49
  • 2
    You need to simplify your code, remove useless constructors and destructors and define your simple(one line) functions in the class definition so the code is reduced. – ChajusSaib Aug 15 '15 at 00:34

2 Answers2

3

There seems to be a misconception of how objects work and are constructed behind this question.

C* objC = new C();

Creates brand new C. The C constructor does absolutely nothing beyond allocating storage, so absolutely nothing is initialized. Because C inherits from B, C's constructor will call the default constructor for B, which does nothing, but calls the default constructor for its parent, A. A's default constuctor does not initialize name and size so their values are undefined. B's default constuctor does not initialize objectA so it is undefined, leading to the segfault.

This C was created by new comes out of some pool of memory, typically the heap, and needs to be returned to this pool with delete when no longer needed. If it is not the program will lose the memory used by C.

The same sample can be performed without dynamic allocation.

C objC;

Creates a C, but does it on the stack. When the stack unrolls at the end of the function or code block (search term: variable scope) the C will be popped off and automatically destroyed. This is typically the better way to operate as it requires no additional memory management. The C looks after itsef and can be considered "fire-and-forget."

Back on topic...

objC->doSomething();

Do something calls the getA method inherited from B which dutifully returns the uninitialized objectA. objectAis promptly used to call getSize with objectA as the concealed this parameter. Since Crom only knows what objectA is actually pointing at it would be a minor miracle if this->size wasn't somewhere crash-provoking.

If the OP expects

A* objA = new A();
objA->Load(1, "Hello Drew Dormann :)");

and

B* objB = new B(objA);

to have some bearing on the state of C. The OP is incorrect. objA and objB are their own entities. They are different objects and every object has its own state.

In order to have C initialize B with something other than the default constructor, you need your C constructor to look more like this:

C::C(A* obj) : B(obj)
{

}

This assigns a pointer to A passed into C to B, using B's B(A*); constructor.

C::C(A* obj, 
     int size,
     string name) : B(obj, size, name)
{

}

B::B(A* obj, 
     int size,
     string name) : A(size, name)
{

}

Cascades all of the parameters needed to fully specify a C all the way down to A.

As B needs to have objectA initialized, I recommend removing B and C's default constructors to force initialization to a meaningful value. If B and C require default constructors for some other purpose, such as storage in a standard container, either getA() needs to be a lot smarter or B's default constructor must initialize objectA to some safe value.

This still leaves the great question of why B contains a pointer to a parent. I'll leave that to the OP to work out.

And while The OP is at it, I recommend reading this: What is The Rule of Three?. Because the next question is likely to be "Dude! Who deleted my objectA"?

Also using namespace std in a header is very super bad. Read here: Why is "using namespace std" considered bad practice?

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
1

Your problem is that objectA in objC points to invalid memory hence in doSomething() you are trying to call the member access operator on an invalid pointer. You can change the default constructor of B to construct an object and have objectA point to it, make sure to free your memory as well!

#include <iostream>
#include <string>

/*#################
// !! class A !! //
#################*/
class A 
{
private:
    int size = 0;
    std::string name;

public:
    int Load(int, const std::string&);

    int getSize() { return size; }
    std::string getName() { return name; }
};

int A::Load(int _size, const std::string &_name)
{
    size = _size;
    name = _name;
    return 0;
}

/*#################
// !! class B !! //
#################*/
class B
{
private:
    A* objectA;

public:
    B() : objectA(new A()) { }
    B(A* obj) : objectA(new A(*obj)) { }

    A* getA() { return objectA; }
    virtual ~B() { delete objectA; }
};

/*#################
// !! class C !! //
#################*/
class C : public B
{
public:
    C() = default;
    int doSomething();
};


int C::doSomething()
{
    // Problem: objectA points to invalid memory
    std::cout << "size = " << getA()->getSize() << std::endl;
    std::cout << "name = " << getA()->getName() << std::endl;

    return 0;
}

/*#################
// !!! main !!!  //
#################*/
int main()
{
    A* objA = new A();
    objA->Load(1, "Hello Drew Dormann :)");

    B* objB = new B(objA);

    C* objC = new C();
    objC->doSomething();
    // free your memory!!!
    delete objA;
    delete objB;
    delete objC;

    return 0;
}
ChajusSaib
  • 167
  • 12
  • 1
    You might want to check that code. It falls into the same trap as OP by not setting `objC`'s `objectA`. – user4581301 Aug 15 '15 at 01:29
  • @user4581301 Could you please elaborate. I don't quite understand what you mean as objC's objectA is default initialized by the constructor of objB, try running it. btw I did not downvote your answer(Don't even have the privilege). – ChajusSaib Aug 15 '15 at 01:39
  • Ah ha! I retract. I didn't see the modification you'd made to `B'`s default constructor. I'd highlight that better if I were you. It makes the segfault go away, but doesn't really solve the problem (I think) of getting `objA` into `objC`. I'm not the downvoter, either, but explain what you did and why and you've got my upvote. This is one of the problems where I don't think the OPs code can be salvaged, and they're better served by a good explanation of why it doesn't work so they can try another path. – user4581301 Aug 15 '15 at 01:51
  • @user4581301 Just read your post and you have come onto it from a better direction then I as well as explaining other points. I just thought the OP in his original code might be accessing an invalid pointer, so I could either have a null pointer but the problem then would be that if he wants to(like in the example) default initialize code, that it would still do what he meant. Honestly this question is all over the place and the OP in my opinion has done a bad job of explaining it. I also would stay away from managing memory myself. – ChajusSaib Aug 15 '15 at 01:58