💡 1.访问”和“初始化本质区别:
- ✅ 访问
protectedNum
:Derived
作为Base
的子类,是可以在自己的函数中访问protectedNum
的。 - ❌ 初始化
protectedNum
:只能通过Base
的构造函数来初始化,因为它是Base
拥有的成员,不是Derived
的成员,Derived
的初始化列表里不能直接初始化它。
📘 展开讲一讲:
🧱 protectedNum
是谁的成员?
它属于 Base
类:
class Base {
protected:
int protectedNum;
};
🔍 能访问它吗?
是的,只要是在 Derived
类的成员函数里,就可以直接访问它,因为继承关系允许子类访问 protected
成员。
✅ 这就像你住在你爸的房子里,屋子里东西你可以随便用,但你不能在房子建好之前,自己去改它的结构。
❌ 为什么不能在 Derived
构造函数初始化列表里初始化 protectedNum
?
这是因为:
- 初始化列表只允许你初始化你自己的成员变量;
- 而
protectedNum
是Base
的成员; - 所以你只能通过调用
Base
的构造函数去初始化它。
你写的这句:
Derived(int num) : protectedNum(num) {}
相当于说:我不调用 Base
构造函数,我直接改你 Base
的东西 —— C++ 不允许这样。
✅ 正确方式是这样:
Derived(int num) : Base(num) {}
或者直接赋值
Derived(int num)
{
protectedNum = num;
};
由 Base
自己初始化它的成员,你只是告诉 Base
你要传什么。
✍️ 类比打个比方:
你(Derived)住在爸妈家(Base),你可以用家里的冰箱(protected 成员),但盖房子(初始化)的时候得让你爸(Base 构造函数)去决定冰箱要不要装、装在哪里,你不能越权。
2.C++ 静态成员变量定义位置详解
一、普通类中的静态成员变量
1. 定义方式
class MyClass {
public:
static MyClass instance;
MyClass();
~MyClass();
};
- 在头文件
.h
中:这是声明 - 在源文件
.cpp
中:必须提供定义
MyClass MyClass::instance;
2. 为什么要放 .cpp
- 头文件可能被多个
.cpp
包含,如果在.h
中定义,会导致多重定义 - C++ 需要在一个且只有一个地方定义并分配静态成员变量的内存
3. 总结
问题 | 答案 |
---|---|
静态变量在类中声明是否自动定义? | 否 |
定义应放哪里? | .cpp |
可以放 .h 吗? | 不推荐,会造成链接错误 |
二、模板类中的静态成员变量
1. 定义方式
template <typename T>
class MyTemplate {
public:
static int count;
};
template <typename T>
int MyTemplate<T>::count = 0; // 必须放在 .h 文件中!
2. 为什么要放 .h
- 模板类不是提前编译好的,而是使用时编译器才生成代码(模板实例化)
- 每种类型的实例(例如
MyTemplate<int>
、MyTemplate<double>
)都是独立的类
- 每种类型的实例(例如
- 编译器在看到
MyTemplate<int>
时,需要能立即看到静态成员的定义
3. 使用 inline
避免多重定义(C++17 起)
template <typename T>
inline int MyTemplate<T>::count = 0;
4. 总结
特性 | 普通类 | 模板类 |
---|---|---|
是否提前确定 | 是 | 否(实例化时生成) |
静态变量定义放哪 | .cpp | .h |
多重定义风险 | 有 | 无,每个模板类型分开 |
推荐方式 | 类外定义一次 | 类内 + inline (C++17) |
三、类内初始化的例外:常量静态成员
可以在类内定义的情况:
static constexpr
或static const int
这类字面值常量:
class Config {
public:
static const int MaxValue = 100; // OK
};
非 constexpr 类型(如 std::string)仍需类外定义:
class Config {
public:
static const std::string name; // 声明
};
// .cpp 中定义
const std::string Config::name = "App";
四、实践建议
- 🧠 普通类静态成员变量 ➜ 放
.cpp
- 🧠 模板类静态成员变量 ➜ 放
.h
,或加inline
(C++17 起) - 🧠 所有类的静态成员 ➜ 不要忘记定义(否则链接失败)