我们可以声明这样的类成员:
class Test {
public:
int a;
}
这是我们如何声明的,但我想知道变量a
的定义位置。
我知道静态类成员,它是静态变量所以它不能在类中定义,它应该在类外定义。所以我认为普通的类成员应该有一个定义的位置,我猜它是隐式定义普通成员的构造函数。是吗?
答案 0 :(得分:5)
对于非静态数据成员,声明和定义是同一个。
所以我认为普通的类成员应该有一个定义的位置,我猜它是隐式定义普通成员的构造函数。
我想我可以看到你来自哪里。对于每个静态数据成员,每种类型只有一个变量实例(对于模板 - 每个模板实例化创建一个不同的类型) - 这就是为什么声明更像是普通变量的extern声明 - 它说“这个变量将有一个地址 - 请求链接器稍后在地址中拼接“。 定义是程序要求编译器为该特定转换单元对象中的变量保留实际内存的位置,链接器将找到该变量并使其可以访问其他已知的转换单元中的代码。并根据声明访问变量。 (这对模板来说有点复杂)。因此,从程序员的角度来看,静态数据成员定义似乎是触发内存分配和安排构造函数运行的源代码行。一旦你编写了定义,分配和构造都会被排序。
对于非静态数据成员,它有很大的不同 - 当编译器解析类定义时,仍然没有实际请求那些非静态数据成员在任何地方被给予任何内存,因为还没有实例对象那种类型。只有当其他一些代码表明需要对象实例时,编译器才需要安排内存(如果不使用placement new
)和构造。换句话说,对于非静态数据,成员定义和分配/构造通常是分离的 - 使用单独的源代码。
这全部递归应用:当一个对象实例本身是静态的或文件/命名空间范围时,当看到定义时,将安排(不一定执行)内存和构造(包括类中的数据成员),如上。但是对象实例经常在堆栈或堆上。无论哪种方式,数据成员的分配和构造代码都是由创建包含对象的方式驱动的,并且与数据成员的定义无关。
答案 1 :(得分:0)
对象的每个实例都在内存中为该对象提供一些保留空间。可能在堆存储中或堆栈上。
该空间内的特定位置存储该对象的每个成员变量。
答案 2 :(得分:0)
a
可以在声明之后,在构造函数中定义,或者完全在类之外定义。这是一个示例,显示a
可以定义的所有方式
class Test {
public:
int a = 5;
Test() {
a = 5;
}
};
int main() {
Test foo;
foo.a = 5;
return 0;
}
答案 3 :(得分:0)
作为一种好的做法,您应该封装数据成员并使用SetA(),GetA()等特定方法管理其定义,并且可以在构造函数中提供默认值