面向对象程序设计是 C++ 的核心章节,涵盖了继承、多态、动态绑定等关键概念。这是理解 C++ 面向对象编程精髓的关键。
1. 继承基础
基本继承语法
// 基类
class Quote {
private:
std::string bookNo; // 私有成员,派生类不能访问
protected:
double price; // 受保护成员,派生类可以访问
public:
Quote() = default;
Quote(const std::string& book, double sales_price)
: bookNo(book), price(sales_price) {}
std::string isbn() const { return bookNo; }
// 虚函数:派生类可以覆盖
virtual double net_price(std::size_t n) const {
return n * price;
}
// 虚析构函数:确保正确释放派生类对象
virtual ~Quote() = default;
};
// 派生类
class Bulk_quote : public Quote { // public 继承
private:
std::size_t min_qty = 0; // 享受折扣的最低购买量
double discount = 0.0; // 折扣额
public:
Bulk_quote() = default;
Bulk_quote(const std::string& book, double p,
std::size_t qty, double disc)
: Quote(book, p), min_qty(qty), discount(disc) {}
// 覆盖基类的虚函数
double net_price(std::size_t n) const override {
if (n >= min_qty) {
return n * (1 - discount) * price;
} else {
return n * price; // 没有折扣
}
}
};
继承中的访问控制
class Base {
public:
int public_member;
protected:
int protected_member;
private:
int private_member; // 派生类不能访问
};
class Public_Derived : public Base {
// public_member 仍然是 public
// protected_member 仍然是 protected
// private_member 不可访问
};
class Protected_Derived : protected Base {
// public_member 变为 protected
// protected_member 仍然是 protected
// private_member 不可访问
};
class Private_Derived : private Base {
// public_member 变为 private
// protected_member 变为 private
// private_member 不可访问
};
2. 虚函数和多态
动态绑定机制
void print_total(std::ostream& os, const Quote& item, std::size_t n) {
// 动态绑定:在运行时根据 item 的实际类型调用正确的 net_price
os << "ISBN: " << item.isbn()
<< " # sold: " << n
<< " total due: " << item.net_price(n) << std::endl;
}
void polymorphism_demo() {
Quote basic("123-456-789", 20.0);
Bulk_quote bulk("123-456-789", 20.0, 10, 0.1); // 10本以上打9折
print_total(std::cout, basic, 15); // 调用 Quote::net_price
print_total(std::cout, bulk, 15); // 调用 Bulk_quote::net_price
// 输出:
// ISBN: 123-456-789 # sold: 15 total due: 300
// ISBN: 123-456-789 # sold: 15 total due: 270
}
虚函数表(vtable)概念
class Base {
public:
virtual void func1() { std::cout << "Base::func1" << std::endl; }
virtual void func2() { std::cout << "Base::func2" << std::endl; }
void func3() { std::cout << "Base::func3" << std::endl; } // 非虚函数
};
class Derived : public Base {
public:
void func1() override { std::cout << "Derived::func1" << std::endl; }
void func3() { std::cout << "Derived::func3" << std::endl; } // 隐藏基类版本
};
void vtable_concept() {
Base* bp = new Derived();
bp->func1(); // 动态绑定:调用 Derived::func1(通过 vtable)
bp->func2(); // 动态绑定:调用 Base::func2(通过 vtable)
bp->func3(); // 静态绑定:调用 Base::func3(编译时确定)
delete bp;
}
3. 抽象基类
纯虚函数和抽象基类
// 抽象基类:包含纯虚函数
class Shape {
protected:
std::string name;
public:
Shape(const std::string& n) : name(n) {}
virtual ~Shape() = default;
// 纯虚函数:派生类必须实现
virtual double area() const = 0;
virtual double perimeter() const = 0;
// 普通虚函数:派生类可以选择性覆盖
virtual void print() const {
std::cout << "Shape: " << name << std::endl;
}
// 非虚函数:派生类继承
const std::string& get_name() const { return name; }
};
// 具体派生类
class Circle : public Shape {
private:
double radius;
public:
Circle(double r, const std::string& n = "Circle")
: Shape(n), radius(r) {}
// 必须实现纯虚函数
double area() const override {
return 3.14159 * radius * radius;
}
double perimeter() const override {
return 2 * 3.14159 * radius;
}
// 可以选择性覆盖普通虚函数
void print() const override {
std::cout << "Circle: " << name << ", radius: " << radius << std::endl;
}
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h, const std::string& n = "Rectangle")
: Shape(n), width(w), height(h) {}
double area() const override {
return width * height;
}
double perimeter() const override {
return 2 * (width + height);
}
};
4. 访问控制和继承
公有、保护、私有继承
class Base {
public:
void pub_func() {}
protected:
void prot_func() {}
private:
void priv_func() {}
};
// 公有继承:接口继承
class PublicDerived : public Base {
public:
void test() {
pub_func(); // OK:公有继承,保持 public
prot_func(); // OK:派生类可以访问 protected
// priv_func(); // 错误:不能访问 private
}
};
// 保护继承:实现继承
class ProtectedDerived : protected Base {
public:
void test() {
pub_func(); // OK:但变为 protected
prot_func(); // OK:仍然是 protected
}
};
// 私有继承:实现继承,不暴露接口
class PrivateDerived : private Base {
public:
void test() {
pub_func(); // OK:但变为 private
prot_func(); // OK:但变为 private
}
};
void access_control_demo() {
PublicDerived d1;
d1.pub_func(); // OK
ProtectedDerived d2;
// d2.pub_func(); // 错误:在派生类中变为 protected
PrivateDerived d3;
// d3.pub_func(); // 错误:在派生类中变为 private
}
5. 构造函数和析构函数在继承中的行为
构造函数调用顺序
class Base {
public:
Base() { std::cout << "Base constructor" << std::endl; }
Base(int x) { std::cout << "Base(" << x << ") constructor" << std::endl; }
virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};
class Derived : public Base {
public:
// 默认调用 Base(),然后执行 Derived 构造函数体
Derived() { std::cout << "Derived constructor" << std::endl; }
// 显式调用基类构造函数
Derived(int x, int y) : Base(x) {
std::cout << "Derived(" << y << ") constructor" << std::endl;
}
~Derived() {
std::cout << "Derived destructor" << std::endl;
// 自动调用 ~Base()
}
};
void constructor_demo() {
std::cout << "Creating d1:" << std::endl;
Derived d1;
std::cout << "\nCreating d2:" << std::endl;
Derived d2(10, 20);
std::cout << "\nDestroying objects:" << std::endl;
}
// 输出:
// Creating d1:
// Base constructor
// Derived constructor
//
// Creating d2:
// Base(10) constructor
// Derived(20) constructor
//
// Destroying objects:
// Derived destructor
// Base destructor
// Derived destructor
// Base destructor
6. 纯虚函数和抽象基类实践
#include <vector>
#include <memory>
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0;
virtual double perimeter() const = 0;
virtual void draw() const = 0;
virtual std::unique_ptr<Shape> clone() const = 0; // 原型模式
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() const override {
return 3.14159 * radius * radius;
}
double perimeter() const override {
return 2 * 3.14159 * radius;
}
void draw() const override {
std::cout << "Drawing Circle with radius " << radius << std::endl;
}
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Circle>(*this);
}
};
class Rectangle : public Shape {
private:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override {
return width * height;
}
double perimeter() const override {
return 2 * (width + height);
}
void draw() const override {
std::cout << "Drawing Rectangle " << width << "x" << height << std::endl;
}
std::unique_ptr<Shape> clone() const override {
return std::make_unique<Rectangle>(*this);
}
};
// 使用多态容器
void shape_system_demo() {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(5.0));
shapes.push_back(std::make_unique<Rectangle>(4.0, 6.0));
// 多态行为
for (const auto& shape : shapes) {
shape->draw();
std::cout << "Area: " << shape->area()
<< ", Perimeter: " << shape->perimeter() << std::endl;
}
// 克隆演示
auto original = std::make_unique<Circle>(10.0);
auto cloned = original->clone();
std::cout << "Original area: " << original->area() << std::endl;
std::cout << "Cloned area: " << cloned->area() << std::endl;
}
7. 类型转换和继承
动态类型转换
class Base {
public:
virtual ~Base() = default;
};
class Derived : public Base {
public:
void derived_method() {
std::cout << "Derived specific method" << std::endl;
}
};
void type_conversion_demo() {
Base* bp = new Derived();
// 向下转换:Base* -> Derived*
Derived* dp = dynamic_cast<Derived*>(bp);
if (dp) { // 转换成功
dp->derived_method();
} else {
std::cout << "Dynamic cast failed" << std::endl;
}
// 引用转换
try {
Derived& dr = dynamic_cast<Derived&>(*bp);
dr.derived_method();
} catch (const std::bad_cast& e) {
std::cout << "Bad cast: " << e.what() << std::endl;
}
delete bp;
}
8. 面向对象设计原则
Liskov 替换原则
// 好的设计:正方形是矩形的特例,但要注意行为一致性
class Rectangle {
protected:
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
virtual void set_width(double w) { width = w; }
virtual void set_height(double h) { height = h; }
double area() const { return width * height; }
};
class Square : public Rectangle {
public:
Square(double side) : Rectangle(side, side) {}
void set_width(double w) override {
width = height = w; // 保持正方形特性
}
void set_height(double h) override {
width = height = h; // 保持正方形特性
}
};
void lsp_demo() {
Rectangle* rect = new Square(5);
rect->set_width(10); // 正确设置正方形的边长
std::cout << "Area: " << rect->area() << std::endl; // 100
delete rect;
}
最佳实践总结
- 对多态基类声明虚析构函数
- 使用 public 继承表示 “is-a” 关系
- 通过引用或指针传递多态类型
- 抽象基类定义接口,具体类实现行为
- 谨慎使用多重继承
- 使用 override 关键字明确表示覆盖虚函数
常见陷阱
class Base {
public:
virtual void func() { std::cout << "Base" << std::endl; }
};
class Derived : public Base {
public:
// 错误:拼写错误,创建了新函数而不是覆盖
void func(int x) { std::cout << "Derived" << std::endl; }
// 正确:使用 override 编译器会检查
void func() override { std::cout << "Derived" << std::endl; }
};
323

被折叠的 条评论
为什么被折叠?



