封装、继承和多态是 C++ 中三个重要的面向对象编程技术。本文将详细介绍这些技术的概念、原理和用法,以帮助读者更好地理解并应用它们。
一、封装
封装是一种面向对象编程的基本概念,它指的是将数据和方法封装在一个对象内部,防止外部通过对象的公共接口直接访问变量和方法,保持了数据的私密性,减少了对象间的耦合。在 C++ 中,我们可以使用类来实现封装。类中的变量和函数可以使用 public、protected 或 private 进行访问控制,分别表示公共、保护和私有属性。
例如,我们定义一个示例类 Student:
class Student {
public:
void setID(int id) {
m_id = id;
}
int getID() {
return m_id;
}
private:
int m_id;
};
在上述代码中,setID() 和 getID() 函数分别用于设置和获取学生的 ID 号。通过将 mid 变量设为私有属性,实现了封装。外部程序无法直接访问 mid 变量,只能通过 setID() 和 getID() 函数来进行,并且通过.public关键字将这俩函数设为公开的, 用户可以在类的外部访问这些函数。
二、继承
继承是一种通过扩展已有类(即父类)来创建新类(即子类)的机制。子类从父类继承了父类的属性和方法,同时可以添加新属性和方法。这种继承关系形成了对象之间的关联,简化了程序设计,提高了代码的重用性。
例如,我们定义一个示例类 Teacher 继承自 Student:
class Teacher: public Student {
public:
void setSalary(double salary) {
m_salary = salary;
}
double getSalary() {
return m_salary;
}
private:
double m_salary;
};
在上述代码中,Teacher 类继承自 Student 类,并添加了一个新的属性 m_salary 和相应的访问函数 setSalary() 和 getSalary()。由于 Teacher 类继承了 Student 类,因此在 Teacher 的对象中不仅可以访问它自己的属性和方法,还可以访问 Student 类中已有的属性和方法。
三、多态
多态是一种在不同的对象上调用同名函数的能力,即在运行期根据对象的类型进行动态绑定的机制。构成多态的三个条件分别是:1.必须存在继承关系;2.继承关系中必须有同名虚函数,并且是覆盖关系(函数原型相同);3.存在基类的指针,通过该指针调用虚函数。C++ 中实现多态的方式有两种:虚函数和函数指针。
1. 虚函数
虚函数是一种在父类中声明的函数,它可以在子类中被重新定义并实现,从而使得在父类的指针或引用上调用该函数时,将根据实际对象类型进行方法动态绑定。虚函数的定义格式为:virtual 返回类型 函数名 参数列表。
例如,我们定义一个 Animal 类,并在其中定义一个虚函数 speak():
class Animal {
public:
virtual void speak() {
cout << "Animal is speaking." << endl;
}
};
接着,我们定义一个 Dog 类,继承自 Animal 类,重定义了 speak() 函数:
class Dog : public Animal {
public:
void speak() {
cout << "Dog is barking." << endl;
}
};
在上述代码中,当我们创建一个 Animal 类的指针或引用,并指向 Dog 类的对象时,调用 speak() 方法时将根据实际对象类型进行动态绑定。因此,执行以下代码得到的输出是 “Dog is barking.”:
Animal* pAnimal = new Dog();
pAnimal->speak();
2. 函数指针
函数指针也可以实现多态的效果。函数指针是指向函数的指针变量,它可以动态地指向不同的函数,从而实现在不同的对象上调用同名函数的能力。在 C++ 中,我们可以定义一个函数指针类型,然后用对象的指针或引用调用该函数指针,从而实现动态绑定。
例如,我们定义一个 Animal 类,并在其中定义一个函数指针类型 fpSpeak 和一个 speak() 函数:
class Animal {
public:
typedef void(*funcPtr)();
funcPtr fpSpeak;
virtual void speak() {
fpSpeak();
}
};
接着,我们定义一个 Dog 类,重定义了 fpSpeak 指针和 speak() 函数:
class Dog : public Animal {
public:
static void dogSpeak() {
cout << "Dog is barking." << endl;
}
Dog() {
fpSpeak = dogSpeak;
}
};
在上述代码中,我们将 fpSpeak 指针赋值为 Dog 类中的静态函数 dogSpeak(),并在构造函数中进行了初始化。然后,我们可以创建一个 Animal 类的指针或引用,并指向 Dog 类的对象,调用 speak() 方法时将根据实际对象类型进行动态绑定。因此,执行以下代码得到的输出也是 “Dog is barking.”:
Animal* pAnimal = new Dog();
pAnimal->speak();
四、总结
封装、继承和多态是面向对象编程中重要的三个技术。封装可以保证数据的隐私性和安全性;继承可以提高代码重用性和简化设计过程;多态可以使得函数调用更加灵活和动态。在实际编程中,我们应该结合具体情况,合理运用这些技术来提高代码的可维护性和可扩展性。