用c ++初始化一个对象

时间:2015-08-14 21:41:30

标签: c++ class initialization

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;
}

为什么我会在doSomething()上收到段错误?

我使用B的孩子处理解析为B的对象。我使用B的孩子来处理A,因为这是更大的事情的一部分这是简化它的唯一方法。

我不明白为什么会这样。

2 个答案:

答案 0 :(得分:3)

似乎对这个问题背后的对象是如何工作的构想存在误解。

C* objC = new C();

创建全新的C.除了分配存储之外,C构造函数绝对没有任何作用,因此绝对没有任何内容被初始化。因为C继承自B,所以C的构造函数将调用B的默认构造函数,它什么都不做,但调用其父元素A的默认构造函数。 A的默认构造函数不会初始化namesize,因此它们的值未定义。 B的默认构造函数没有初始化objectA所以它是未定义的,导致了段错误。

这个C由new创建,来自一些内存池,通常是堆,当需要时需要使用delete返回到此池。如果不是,程序将丢失C使用的内存。

可以在没有动态分配的情况下执行相同的样本。

C objC;

创建一个C,但是在堆栈上执行。当堆栈在函数或代码块(搜索项:变量范围)结束时展开时,C将弹出并自动销毁。这通常是更好的操作方式,因为它不需要额外的内存管理。 C关注itsef并且可以被认为是“永远不会忘记”。

回到主题......

objC->doSomething();

执行某些操作调用从B继承的getA方法,该方法尽职地返回未初始化的objectAobjectA会立即用getSize作为隐藏objectA参数来调用this。由于Crom只知道objectA实际指向的是什么,如果this->size不是一个引人注目的地方,那将是一个小小的奇迹。

如果OP需要

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

B* objB = new B(objA);

对C的状态有一些影响.OP是不正确的。 objAobjB是他们自己的实体。它们是不同的对象,每个对象都有自己的状态。

为了让C使用默认构造函数之外的其他东西初始化B,你需要你的C构造函数看起来更像这样:

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

}

这使用B的B(A*);构造函数将指向A的指针分配给C到B.

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

}

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

}

将完全指定C所需的所有参数级联到A。

由于B需要初始化objectA,我建议删除B和C的默认构造函数以强制初始化为有意义的值。如果B和C需要默认构造函数用于其他目的,例如存储在标准容器中,则getA()需要更加智能,或者B的默认构造函数必须将objectA初始化为某个安全值。

这仍然留下了为什么B包含指向父级的指针的大问题。我会把它留给OP解决。

虽然OP就是这样,但我建议你阅读:What is The Rule of Three?。因为下一个问题可能是“伙计!谁deleted我的objectA”?

标题中的using namespace std也非常糟糕。请在此处阅读:Why is "using namespace std" considered bad practice?

答案 1 :(得分:1)

您的问题是objectA中的objC指向无效内存,因此在doSomething()中您尝试在无效指针上调用成员访问运算符。你可以改变B的默认构造函数来构造一个对象并让objectA指向它,同时确保释放你的内存!

#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;
}