成员变量必须声明在类定义内部的花括号内,不能在函数或全局作用域中;const和引用类型成员必须用初始化列表初始化,static成员需类内声明+类外定义(c++17可用inline static)。

成员变量声明必须写在类定义内部
成员变量不是在函数里、也不是在全局作用域声明的,它必须出现在 class 或 struct 的花括号内。编译器靠这个位置识别“这是属于这个类型的变量”,而不是局部变量或全局变量。
常见错误是把成员变量写在构造函数里,比如:
class Person {
public:
Person() {
int age = 0; // ❌ 这是局部变量,不是成员变量
}
};
正确写法是:
class Person {
private:
int age; // ✅ 声明在类体内,未初始化
std::string name = "unknown"; // ✅ C++11 起支持默认成员初始化
public:
Person() = default;
};
- 访问控制符(
public/private/protected)决定谁能看到它,不加默认是private(struct默认是public) - 声明时不能带初始化表达式(如
int x = get_value();),除非用 C++11 的非静态数据成员初始化(NSDMI)语法 - 静态成员变量要额外在类外定义一次,比如
int MyClass::count;
const 成员变量必须用成员初始化列表
一旦声明为 const,就不能在构造函数体里赋值——它没有“可修改”的阶段了。必须在进入构造函数体前就初始化好。
class Config {
private:
const int timeout;
const std::string env;
public:
Config(int t, std::string e) : timeout(t), env(std::move(e)) {
// ✅ 正确:成员初始化列表中完成初始化
// timeout = t; // ❌ 编译错误:const 成员不可赋值
}
};
- 引用类型成员(
int&、const std::string&)也必须走初始化列表 - 如果类有多个 const 成员,初始化顺序严格按它们在类中声明的顺序,和初始化列表里的书写顺序无关
- 忘记初始化 const 成员会直接报错,错误信息通常是
uninitialized const member
static 成员变量要分两步:声明 + 定义
类内只是声明,真正分配内存必须在类外定义一次。否则链接时会报 undefined reference。
class Counter {
public:
static int count; // ✅ 声明(放头文件里)
};
int Counter::count = 0; // ✅ 定义(放 .cpp 文件里,且只能有一处)
- 如果不初始化,
static内置类型会被零初始化;但自定义类型必须显式调用构造函数,比如static std::vector<int> data;</int>需要定义为std::vector<int> Counter::data;</int> - C++17 引入
inline static,允许在类内直接定义:inline static int count = 0;,这样就不需要类外定义了 - 模板类的
static成员变量定义位置更敏感,容易因头文件多次包含导致重复定义,inline static是更安全的选择
别把成员变量和成员函数参数名搞混
名字一样不会报错,但容易引发隐匿(shadowing)问题,尤其是忘了用 this-> 或初始化列表时。
class Point {
double x, y;
public:
Point(double x, double y) {
x = x; // ❌ 实际是参数给自己赋值,成员 x 没变
this->x = x; // ✅ 显式指定成员
// 或者更好:用初始化列表 Point(double x, double y) : x(x), y(y) {}
}
};
- 现代编译器(如 Clang/GCC 加
-Wshadow)会警告这种命名冲突 - 一些团队约定成员变量加下划线后缀(
x_)或前缀(m_x),就是为了避免混淆 - 初始化列表里可以安全使用同名参数,因为语法上明确区分了左右:
: x(x)左边是成员,右边是参数
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











