10、面向对象介绍
你肯定知道,C++
是一门支持面向对象(Object-Oriented Programming,简称OOP
)的语言,那什么是面向对象呢?
可以理解为面向对象是一种编程范式,它以“对象”为核心,将数据和操作数据的方法封装在一起,通过抽象、继承、多态等机制来组织代码。面向对象的主要目标是提高代码的可复用性、可维护性和可扩展性。
面向对象
面向对象三要素:继承、封装、多态。
核心概念
对象
对象是面向对象编程的基本单元,它是一个具体的实例,包含数据(属性)和行为(方法)。例如,在一个学生管理系统中,每个学生可以看作一个对象,具有姓名、年龄、学号等属性,以及选课、考试等方法。
类
类是对象的模板或蓝图,它定义了对象的属性和方法。类是抽象的,而对象是类的具体实例。例如,Student
类可以定义学生的共同属性和行为,而具体的某个学生(张三)是Student
类的一个对象。
封装
封装是将数据(属性)和操作数据的方法(行为)绑定在一起,并隐藏内部实现细节。通过访问修饰符(如public
、private
、protected
),可以控制数据的访问权限,提高代码的安全性和可维护性。
继承
继承是一种机制,允许一个类(派生类)基于另一个类(基类)创建新的类。派生类继承了基类的属性和方法,并可以扩展或修改这些属性和方法。继承的主要目的是实现代码的复用。
多态
多态是指同一个接口可以表现出不同的行为。通过多态,可以在运行时决定调用哪个类的具体实现。一般通过虚函数和抽象类来实现多态。
优势
- 模块化:将代码划分为独立的类和对象,便于管理和维护。
- 可复用性:通过继承和组合,可以复用已有的代码,减少重复劳动。
- 可扩展性:通过多态和抽象类,可以轻松扩展程序的功能。
- 可维护性:封装隐藏了内部实现细节,降低了代码的耦合性,方便后续修改和调试。
代码示例
#include <iostream>
#include <string>
// 定义一个类
class Student {
private:
std::string name; // 私有属性
int age;
public:
// 构造函数
Student(std::string n, int a) : name(n), age(a) {}
// 公有方法
void displayInfo() {
std::cout << "Name: " << name << ", Age: " << age << std::endl;
}
// 设置年龄
void setAge(int a) {
if (a > 0) {
age = a;
} else {
std::cout << "Invalid age!" << std::endl;
}
}
// 获取年龄
int getAge() {
return age;
}
};
int main() {
// 创建对象
Student student1("Alice", 20);
Student student2("Bob", 22);
// 调用对象的方法
student1.displayInfo(); // 输出:Name: Alice, Age: 20
student2.displayInfo(); // 输出:Name: Bob, Age: 22
// 修改对象的属性
student1.setAge(21);
std::cout << "Alice's new age: " << student1.getAge() << std::endl; // 输出:Alice's new age: 21
return 0;
}
类的继承与派生
继承的基本概念
继承是面向对象编程的重要特性之一,它允许一个类(派生类)基于另一个类(基类)来创建新的类。派生类继承了基类的属性和方法,同时可以扩展或修改这些属性和方法。
- 基类(父类):被继承的类。
- 派生类(子类):继承基类的类。
继承的语法
继承的语法如下:
class 派生类名 : 访问修饰符 基类名 {
// 派生类的成员
};
访问修饰符可以是public
、protected
或private
,决定了基类成员在派生类中的访问权限。
继承的类型
- 公有继承(public):基类的
public
成员在派生类中仍然是public
,protected
成员仍然是protected
。 - 保护继承(protected):基类的
public
和protected
成员在派生类中都变为protected
。 - 私有继承(private):基类的
public
和protected
成员在派生类中都变为private
。
代码示例
#include <iostream>
// 基类
class Animal {
public:
void eat() {
std::cout << "Animal is eating." << std::endl;
}
protected:
void sleep() {
std::cout << "Animal is sleeping." << std::endl;
}
};
// 派生类
class Dog : public Animal {
public:
void bark() {
std::cout << "Dog is barking." << std::endl;
sleep(); // 可以访问基类的protected成员
}
};
int main() {
Dog dog;
dog.eat(); // 调用基类的public成员函数
dog.bark(); // 调用派生类的成员函数
// dog.sleep(); // 错误:sleep是protected成员,不能在类外访问
return 0;
}
多态
多态的概念
多态是指同一个接口可以表现出不同的行为。在C++
中,多态主要通过虚函数和抽象类来实现。
虚函数
虚函数是在基类中使用virtual
关键字声明的函数,允许在派生类中重写该函数。通过基类指针或引用调用虚函数时,实际调用的是派生类的函数。
#include <iostream>
class Animal {
public:
virtual void makeSound() {
std::cout << "Animal makes a sound." << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
std::cout << "Dog barks." << std::endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
std::cout << "Cat meows." << std::endl;
}
};
int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();
animal1->makeSound(); // 输出:Dog barks.
animal2->makeSound(); // 输出:Cat meows.
delete animal1;
delete animal2;
return 0;
}
抽象类
抽象类是不能实例化的类,通常用于定义接口。抽象类中至少包含一个纯虚函数(用**= 0
**声明)。
#include <iostream>
// 抽象类
class Shape {
public:
virtual void draw() = 0; // 纯虚函数
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing a circle." << std::endl;
}
};
class Square : public Shape {
public:
void draw() override {
std::cout << "Drawing a square." << std::endl;
}
};
int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();
shape1->draw(); // 输出:Drawing a circle.
shape2->draw(); // 输出:Drawing a square.
delete shape1;
delete shape2;
return 0;
}
静态成员与友元函数
静态成员
静态成员属于类本身,而不是类的某个对象。静态成员变量在类的所有对象之间共享,静态成员函数只能访问静态成员变量。
#include <iostream>
class Counter {
public:
static int count; // 静态成员变量
Counter() {
count++;
}
static void showCount() { // 静态成员函数
std::cout << "Count: " << count << std::endl;
}
};
int Counter::count = 0; // 初始化静态成员变量
int main() {
Counter c1, c2, c3;
Counter::showCount(); // 输出:Count: 3
return 0;
}
友元函数
友元函数可以访问类的私有成员和保护成员。友元函数不是类的成员函数,但需要在类中声明。
#include <iostream>
class Box {
private:
int width;
public:
Box(int w) : width(w) {}
friend void printWidth(Box box); // 声明友元函数
};
void printWidth(Box box) {
std::cout << "Width: " << box.width << std::endl; // 访问私有成员
}
int main() {
Box box(10);
printWidth(box); // 输出:Width: 10
return 0;
}
this指针与成员函数重载
this指针
this
指针是一个隐含的指针,指向当前对象的地址。它用于在类的成员函数中访问当前对象的成员。
#include <iostream>
class MyClass {
private:
int value;
public:
void setValue(int value) {
this->value = value; // 使用this指针区分成员变量和参数
}
void printValue() {
std::cout << "Value: " << this->value << std::endl;
}
};
int main() {
MyClass obj;
obj.setValue(42);
obj.printValue(); // 输出:Value: 42
return 0;
}
成员函数重载
成员函数重载是指在同一个类中定义多个同名函数,但参数列表不同。
#include <iostream>
class Math {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
};
int main() {
Math math;
std::cout << math.add(2, 3) << std::endl; // 输出:5
std::cout << math.add(2.5, 3.5) << std::endl; // 输出:6
return 0;
}
练习
- 设计一个基类
Vehicle
,包含虚函数start()
和stop()
。派生出两个类Car
和Bike
,分别重写start()
和stop()
函数。 - 实现一个类
Calculator
,包含静态成员函数add
、subtract
、multiply
和divide
,分别用于执行加、减、乘、除运算。 - 设计一个类
Student
,包含私有成员name
和age
,并提供一个友元函数printStudent
,用于打印学生的信息。
