C++ 第10课:类的大小、继承与权限控制
课程目标:
- 理解 C++ 中类的大小计算方式
- 掌握类的继承机制,区分基类和派生类
- 理解不同继承方式对成员访问权限的影响
- 学会使用 protected 和 final 关键字控制成员访问和继承
1. sizeof(自定义类)
类的大小指的是该类型对象所占用的内存空间大小。
cpp
class MyClass {
public:
int publicVar;
void publicFunc() {}
private:
int privateVar;
static int staticVar;
};
int main() {
MyClass obj;
cout << sizeof(obj) << endl; // 输出 8,因为只计算两个 int 成员变量的大小
cout << sizeof(MyClass) << endl; // 输出 8,与 sizeof(obj) 相同
return 0;
}
要点:
- 类的大小与其对象的大小一致。
- 类的大小是所有非静态成员变量大小之和,与成员函数和静态成员变量无关。
- 类成员的构造顺序:先执行构造函数初始化列表,同时执行父类构造函数,最后构造成员。
- 类内部编译顺序:先编译所有成员变量,然后编译成员函数。
- 类外部编译顺序:按照代码行顺序编译。
- 内存对齐:为了提高 CPU 访问效率,成员变量会按照 4 字节对齐,不足 4 的倍数时会进行填充。
2. 类的继承
继承是面向对象编程中一个重要的概念,允许我们创建一个新类(派生类)基于现有类(基类),从而实现代码复用和扩展。
cpp
// 基类
class Animal {
public:
string name;
Animal(string n) : name(n) {}
void eat() { cout << name << " is eating." << endl; }
};
// 派生类
class Bird : public Animal {
public:
int wingspan;
Bird(string n, int w) : Animal(n), wingspan(w) {}
void fly() { cout << name << " is flying." << endl; }
};
int main() {
Bird sparrow("Sparrow", 20);
sparrow.eat(); // 调用基类的成员函数
sparrow.fly(); // 调用派生类的成员函数
return 0;
}
要点:
- 子类继承父类,拥有父类所有非私有成员。
- 可以多层次继承,形成继承链。
- 父类的私有成员在子类中无法访问,但受保护的成员可以访问。
- 继承方式:
- 公有继承 (public):父类成员的访问权限在子类中保持不变。
- 私有继承 (private):父类所有成员在子类中都变成私有权限。
- 函数重写:子类可以定义与父类同名函数,实现功能的覆盖。
- 子类成员可以覆盖父类的同名成员,无论是函数还是变量。
3. protected 访问权限
protected
关键字用于定义受保护的成员,这些成员只能在类内部和派生类中访问,无法从外部访问。
cpp
class Animal {
protected:
int age;
};
class Dog : public Animal {
public:
void setAge(int a) { age = a; } // 可以访问 protected 成员
};
int main() {
Dog myDog;
// myDog.age = 5; // 错误,无法直接访问 protected 成员
myDog.setAge(5);
return 0;
}
要点:
protected
权限用于保护成员,限制其访问范围。- 私有继承和保护继承会缩小继承成员的访问权限。
- 公有继承保持继承成员的访问权限不变。
- 基类的
private
成员在派生类中无法访问。
4. final 关键字
final
关键字可以用于阻止类被继承,或者阻止虚函数被重写。
cpp
class Shape {
public:
virtual void draw() = 0;
};
class Circle : public Shape {
public:
void draw() final { /* 实现 */ } // final 阻止该函数被重写
};
//class SubCircle : public Circle { ... }; // 错误,Circle 类被 final 修饰,无法被继承
要点:
- 使用
final
修饰的类无法被继承。 - 使用
final
修饰的虚函数无法被重写。
课后作业:设计一个简单的员工管理系统
目标:
- 运用所学的类、对象和继承的知识,设计一个简单的员工管理系统。
- 体现面向对象编程中代码复用和扩展的优势。
需求:
- 员工类 (Employee):
- 基类,包含员工的共同属性(例如姓名、工号、部门等),以及计算薪水 (
calculateSalary
) 的函数(可设置为返回固定值或简单计算)。
- 基类,包含员工的共同属性(例如姓名、工号、部门等),以及计算薪水 (
- 经理类 (Manager):
- 继承自
Employee
类,增加特有属性:管理津贴 (bonus
)。 - 重写
calculateSalary
函数,计算方式为:员工基础薪水 + 管理津贴。
- 继承自
- 销售员类 (Salesperson):
- 继承自
Employee
类,增加特有属性:销售额 (salesVolume
) 和提成比例 (commissionRate
)。 - 重写
calculateSalary
函数,计算方式为:员工基础薪水 + 销售额 * 提成比例。
- 继承自
提示:
- 思考共同特征和区别,将其抽象成类和成员。
- 使用合适的访问权限控制成员的可见性和可访问性。
- 可以使用构造函数初始化列表为成员变量賦值。
- 编写测试代码验证类的功能和继承关系。