C++中初始化一个对象
Initializing an object in c++
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,因为这是更大的对象的一部分这是简化它的唯一方法。
我不明白为什么会这样。
您的问题是 objC
中的 objectA
指向无效内存,因此在 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;
}
似乎对object如何工作以及这个问题背后的构造存在误解。
C* objC = new C();
创建全新的 C。C 构造函数除了分配存储之外什么都不做,所以什么都没有初始化。因为C继承自B,C的构造函数会调用B
的默认构造函数,什么都不做,而是调用其parent的默认构造函数,A。
A 的默认构造函数不会初始化 name
和 size
,因此它们的值未定义。 B 的默认构造函数没有初始化 objectA
所以它是未定义的,导致段错误。
这个 C 是由 new
创建的,来自某个内存池,通常是堆,并且在不再需要时需要用 delete
返回到这个池中。如果不是,程序将丢失 C 使用的内存。
无需动态分配即可执行相同样本。
C objC;
创建一个 C,但在堆栈上执行。当堆栈在函数或代码块(搜索词:变量范围)的末尾展开时,C 将被弹出并自动销毁。这通常是更好的操作方式,因为它不需要额外的内存管理。 C 照顾它自己,可以考虑 "fire-and-forget."
回到主题...
objC->doSomething();
做一些事情调用从 B 继承的 getA
方法,它尽职地 returns 未初始化的 objectA
。 objectA
直接用于调用getSize
,objectA
作为隐藏的this
参数。由于 Crom 只知道 objectA
实际上指向的是什么,如果 this->size
不在 crash-provoking 的某个地方,那将是一个小小的奇迹。
如果 OP 期望
A* objA = new A();
objA->Load(1, "Hello Drew Dormann :)");
和
B* objB = new B(objA);
对C的状态有一些影响。OP不正确。 objA
和 objB
是它们自己的实体。它们是不同的 object,每个 object 都有自己的状态。
为了让 C 使用默认构造函数以外的东西初始化 B,您需要 C 构造函数看起来更像这样:
C::C(A* obj) : B(obj)
{
}
这使用 B 的 B(A*);
构造函数将传递到 C 的指向 A 的指针分配给 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 包含指向 a parent 的指针。我会把它留给 OP 解决。
虽然 OP 正在做这件事,但我建议阅读这篇文章:What is The Rule of Three?。因为下一个问题很可能是"Dude! Who deleted
my objectA
"?
header 中的 using namespace std
也非常糟糕。阅读此处:Why is "using namespace std" considered bad practice?
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,因为这是更大的对象的一部分这是简化它的唯一方法。
我不明白为什么会这样。
您的问题是 objC
中的 objectA
指向无效内存,因此在 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;
}
似乎对object如何工作以及这个问题背后的构造存在误解。
C* objC = new C();
创建全新的 C。C 构造函数除了分配存储之外什么都不做,所以什么都没有初始化。因为C继承自B,C的构造函数会调用B
的默认构造函数,什么都不做,而是调用其parent的默认构造函数,A。
A 的默认构造函数不会初始化 name
和 size
,因此它们的值未定义。 B 的默认构造函数没有初始化 objectA
所以它是未定义的,导致段错误。
这个 C 是由 new
创建的,来自某个内存池,通常是堆,并且在不再需要时需要用 delete
返回到这个池中。如果不是,程序将丢失 C 使用的内存。
无需动态分配即可执行相同样本。
C objC;
创建一个 C,但在堆栈上执行。当堆栈在函数或代码块(搜索词:变量范围)的末尾展开时,C 将被弹出并自动销毁。这通常是更好的操作方式,因为它不需要额外的内存管理。 C 照顾它自己,可以考虑 "fire-and-forget."
回到主题...
objC->doSomething();
做一些事情调用从 B 继承的 getA
方法,它尽职地 returns 未初始化的 objectA
。 objectA
直接用于调用getSize
,objectA
作为隐藏的this
参数。由于 Crom 只知道 objectA
实际上指向的是什么,如果 this->size
不在 crash-provoking 的某个地方,那将是一个小小的奇迹。
如果 OP 期望
A* objA = new A();
objA->Load(1, "Hello Drew Dormann :)");
和
B* objB = new B(objA);
对C的状态有一些影响。OP不正确。 objA
和 objB
是它们自己的实体。它们是不同的 object,每个 object 都有自己的状态。
为了让 C 使用默认构造函数以外的东西初始化 B,您需要 C 构造函数看起来更像这样:
C::C(A* obj) : B(obj)
{
}
这使用 B 的 B(A*);
构造函数将传递到 C 的指向 A 的指针分配给 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 包含指向 a parent 的指针。我会把它留给 OP 解决。
虽然 OP 正在做这件事,但我建议阅读这篇文章:What is The Rule of Three?。因为下一个问题很可能是"Dude! Who deleted
my objectA
"?
header 中的 using namespace std
也非常糟糕。阅读此处:Why is "using namespace std" considered bad practice?