C++面向对象编程习题详解:从类设计到STL实战的完整指南

📅 2026/7/14 7:15:16
C++面向对象编程习题详解:从类设计到STL实战的完整指南
1. 项目概述为什么我们需要“习题详解”如果你正在学习C面向对象程序设计手头有一本教材或一份课程大纲里面塞满了各种练习题从简单的类定义到复杂的多态应用再到模板和STL的实战。你可能会发现看书看懂了听课听明白了但一关上书本面对那些需要自己动手敲代码的题目大脑却一片空白。或者你吭哧吭哧写了几十行代码编译通过了运行结果却和预期大相径庭调试半天也找不到头绪。这正是“C面向对象程序设计习题详解”这个项目存在的核心价值——它不是一个简单的答案集合而是一个从问题出发拆解思路、分析陷阱、提供可运行代码并解释其背后“为什么”的深度指南。面向对象编程OOP是C的精髓也是区分“会写C风格代码”和“会用C解决问题”的关键门槛。类与对象、封装、继承、多态、运算符重载、模板……这些概念单看理论并不难但如何将它们有机地组合起来设计出结构清晰、易于维护、可扩展的程序才是真正的挑战。习题正是将理论转化为肌肉记忆的“磨刀石”。然而市面上的许多教材习题要么只有干巴巴的题目要么只提供一个最终答案缺少中间思考过程和错误示范这让自学变得异常困难。因此这个“习题详解”项目旨在扮演一个“无声的导师”角色。它不仅仅告诉你“答案是什么”更重要的是带你走过“如何得到这个答案”的完整路径题目到底在考察哪个核心概念常见的理解误区有哪些如何设计类的接口和数据成员继承体系中基类析构函数为什么要声明为虚函数深拷贝和浅拷贝在什么时候会埋下隐患模板特化该怎么用通过拆解一道道典型习题我们将把OOP的知识点串联起来形成一张牢固的知识网络。无论你是正在备战学校考试、准备技术面试还是希望夯实C基础以便进行项目开发跟随这些详解一步步思考和实践都能让你对C面向对象的理解上升一个实实在在的台阶。2. 核心概念与常见习题类型深度解析在动手解题之前我们必须对C面向对象的核心概念及其在习题中的常见考察形式有一个系统的认识。很多错误并非源于代码语法而是源于对概念理解的偏差。2.1 类与对象封装的艺术这是OOP的基石。习题通常从定义一个简单的类开始例如Student、Rectangle、BankAccount。这里的关键不在于写出class关键字而在于如何设计。核心考察点访问控制public, private, protected哪些数据应该隐藏private哪些接口应该暴露public。一个常见的错误是将所有数据成员都设为 public这完全破坏了封装性。构造函数与析构函数默认构造函数、拷贝构造函数、移动构造函数、赋值运算符、析构函数合称“Big Three”或“Big Five”。习题常要求你手动实现它们特别是当类管理动态内存如char* name、int* array时。成员函数分为普通成员函数和const成员函数。const成员函数承诺不修改对象状态这对于保证程序的正确性至关重要。一道典型习题设计一个String类模拟标准库std::string的基本功能构造、拷贝、赋值、连接、输出等。注意实现这类“资源管理类”是理解C底层内存管理的绝佳机会。你必须考虑深拷贝与浅拷贝的区别。默认的拷贝构造函数和赋值运算符进行的是浅拷贝逐位复制如果类内有指针会导致两个对象指向同一块内存析构时会被重复释放造成程序崩溃。// 一个存在严重问题的String类浅拷贝问题 class BadString { private: char* data; public: BadString(const char* str ) { data new char[strlen(str) 1]; strcpy(data, str); } ~BadString() { delete[] data; } // 默认的拷贝构造函数和赋值运算符是浅拷贝 }; int main() { BadString s1(Hello); BadString s2 s1; // 浅拷贝s2.data 和 s1.data 指向同一地址 return 0; } // 析构时同一块内存被delete两次程序崩溃详解思路解决之道就是实现深拷贝。我们需要自定义拷贝构造函数和拷贝赋值运算符。class GoodString { private: char* data; public: // 构造函数 GoodString(const char* str ) { data new char[strlen(str) 1]; strcpy(data, str); } // 1. 拷贝构造函数 (深拷贝) GoodString(const GoodString other) { data new char[strlen(other.data) 1]; strcpy(data, other.data); } // 2. 拷贝赋值运算符 (深拷贝并处理自赋值) GoodString operator(const GoodString other) { if (this ! other) { // 关键防止自赋值 a a delete[] data; // 释放原有资源 data new char[strlen(other.data) 1]; strcpy(data, other.data); } return *this; // 返回*this以支持链式赋值 a b c } // 析构函数 ~GoodString() { delete[] data; } // 其他成员函数... };2.2 继承与多态构建层次体系继承用于表达“是一个is-a”的关系是实现代码复用的重要手段。多态则允许我们通过基类指针或引用来操作派生类对象是设计灵活、可扩展系统的关键。核心考察点继承方式public, protected, private 继承的区别。绝大多数情况下应使用 public 继承。构造函数与析构函数的调用顺序创建派生类对象时先调用基类构造函数再调用派生类构造函数析构时顺序相反。函数重写Override与虚函数virtual派生类重新定义基类的虚函数。这里必须区分“重写”override和“重载”overload。纯虚函数与抽象类含有纯虚函数virtual void func() 0;的类是抽象类不能实例化用于定义接口。虚析构函数这是一个极易出错且面试必考的点如果基类指针指向派生类对象并且基类的析构函数不是虚函数那么通过基类指针删除对象时只会调用基类的析构函数而不会调用派生类的析构函数导致派生类独有的资源如动态内存泄漏。一道典型习题设计一个图形Shape类层次包含基类Shape以及派生类Circle、Rectangle。Shape类有计算面积area()和周长perimeter()的接口。使用基类指针数组存储不同图形并统一计算它们的总面积。详解思路Shape类应该是一个抽象类因为“形状”本身无法计算面积和周长。所以area()和perimeter()应声明为纯虚函数。派生类Circle、Rectangle需要重写这些纯虚函数提供具体实现。在main函数中可以创建Shape*数组或vectorShape*存入不同的派生类对象地址。关键Shape的析构函数必须声明为虚函数以确保正确释放资源。#include iostream #include vector #include cmath class Shape { public: virtual double area() const 0; // 纯虚函数使Shape成为抽象类 virtual double perimeter() const 0; virtual ~Shape() {} // 虚析构函数至关重要 }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} virtual double area() const override { return 3.14159 * radius * radius; } virtual double perimeter() const override { return 2 * 3.14159 * radius; } }; class Rectangle : public Shape { private: double width, height; public: Rectangle(double w, double h) : width(w), height(h) {} virtual double area() const override { return width * height; } virtual double perimeter() const override { return 2 * (width height); } }; int main() { std::vectorShape* shapes; shapes.push_back(new Circle(5.0)); shapes.push_back(new Rectangle(4.0, 6.0)); shapes.push_back(new Circle(2.0)); double totalArea 0; for (Shape* s : shapes) { totalArea s-area(); // 多态调用s指向Circle则调用Circle::area() std::cout Area: s-area() , Perimeter: s-perimeter() std::endl; } std::cout Total area: totalArea std::endl; // 释放内存 for (Shape* s : shapes) { delete s; // 因为Shape有虚析构函数这里会正确调用Circle或Rectangle的析构函数 } return 0; }2.3 运算符重载让自定义类型用起来像内置类型运算符重载允许我们为自定义的类类型赋予类似内置类型的运算能力如,-,,,[]等。核心考察点成员函数重载 vs. 友元函数重载,-,,-这类运算符通常重载为成员函数而,输入输出流运算符由于左侧操作数是流对象而非自定义类对象必须重载为友元函数或普通函数。返回类型赋值运算符、复合赋值运算符通常返回自身引用ClassName以支持链式操作算术运算符通常返回一个新对象值。自增/自减运算符的前置与后置通过一个额外的int形参哑元来区分后置版本。一道典型习题为上述GoodString类重载运算符以实现字符串连接重载运算符以实现输出。详解思路class GoodString { // ... 之前的成员数据构造拷贝析构 ... public: // 重载 运算符成员函数版本连接两个GoodString GoodString operator(const GoodString other) const { GoodString newStr; // 创建一个临时对象 delete[] newStr.data; // 注意默认构造已分配了空串的内存需要先释放 newStr.data new char[strlen(data) strlen(other.data) 1]; strcpy(newStr.data, data); strcat(newStr.data, other.data); return newStr; // 返回值注意这里会触发拷贝构造编译器可能优化为RVO } // 重载 运算符成员函数修改自身 GoodString operator(const GoodString other) { char* temp new char[strlen(data) strlen(other.data) 1]; strcpy(temp, data); strcat(temp, other.data); delete[] data; data temp; return *this; } // 重载 运算符必须为非成员函数通常声明为友元 friend std::ostream operator(std::ostream os, const GoodString str); }; // 运算符的实现非成员函数 std::ostream operator(std::ostream os, const GoodString str) { os str.data; return os; } // 使用示例 int main() { GoodString s1(Hello, ); GoodString s2(World!); GoodString s3 s1 s2; // 调用 operator std::cout s3 std::endl; // 调用 operator s1 s2; // 调用 operator std::cout s1 std::endl; return 0; }2.4 模板与STL泛型编程的强大工具模板允许我们编写与类型无关的通用代码。标准模板库STL提供了容器vector, map, set等、算法sort, find等和迭代器是C实际开发中不可或缺的部分。核心考察点函数模板与类模板如何定义和使用。模板特化为特定类型提供特殊实现。STL容器的选择与使用vectorvslistmapvsunordered_map的性能与特性区别。迭代器理解不同种类的迭代器输入、输出、前向、双向、随机访问及其适用场景。Lambda表达式C11起与STL算法如sort,for_each配合使用编写简洁的匿名函数。一道典型习题实现一个通用的findMax函数模板能够找出数组中的最大元素。再使用STL的vector和sort算法对学生Student对象按成绩进行排序。详解思路#include iostream #include vector #include algorithm #include string // 1. 通用的findMax函数模板 template typename T const T findMax(const T arr[], int size) { int maxIndex 0; for (int i 1; i size; i) { if (arr[maxIndex] arr[i]) { // 依赖类型T的运算符 maxIndex i; } } return arr[maxIndex]; } // 2. 学生类用于STL排序演示 class Student { public: std::string name; int score; Student(const std::string n, int s) : name(n), score(s) {} // 为了能让sort排序我们需要定义比较规则。方式有多种 // a) 重载 运算符 bool operator(const Student other) const { return score other.score; // 按成绩升序 // 如果想按成绩降序可以写 return score other.score; } }; // b) 也可以定义一个独立的比较函数 bool compareByScore(const Student a, const Student b) { return a.score b.score; } int main() { // 使用findMax模板 int intArr[] {3, 1, 4, 1, 5, 9}; std::cout Max int: findMax(intArr, 6) std::endl; double doubleArr[] {2.7, 3.1, 1.4}; std::cout Max double: findMax(doubleArr, 3) std::endl; // 使用STL vector和sort std::vectorStudent students; students.push_back(Student(Alice, 85)); students.push_back(Student(Bob, 92)); students.push_back(Student(Charlie, 78)); // 排序方法1使用Student类重载的 运算符 std::sort(students.begin(), students.end()); for (const auto s : students) { std::cout s.name : s.score std::endl; } std::cout --- std::endl; // 排序方法2使用自定义的比较函数 std::sort(students.begin(), students.end(), compareByScore); // 排序方法3使用Lambda表达式更灵活常用于临时比较逻辑 std::sort(students.begin(), students.end(), [](const Student a, const Student b) { return a.name b.name; }); // 按名字排序 for (const auto s : students) { std::cout s.name : s.score std::endl; } return 0; }3. 综合实战一个简易“图书馆管理系统”的设计与实现让我们通过一个稍复杂的综合习题将上述多个知识点串联起来。题目要求设计一个简单的图书馆管理系统包含Book图书、User用户、Library图书馆类。支持借书、还书、查询书籍信息、查询用户借阅记录等功能。3.1 类设计思路与UML关系图概念首先我们需要厘清类之间的关系。Book类核心数据成员包括 ISBN唯一标识、书名、作者、是否被借出等。User类核心数据成员包括用户ID、姓名、当前借阅的书籍列表可以用vectorBook*或vectorstring存储ISBN。Library类作为系统核心管理所有的Book和User对象。它包含两个主要容器mapstring, Book* books以ISBN为键和mapstring, User* users以用户ID为键。并提供借阅、归还、查询等方法。Library与Book、User是聚合关系拥有。User与Book是关联关系通过借阅记录连接。3.2 核心类的代码实现Book.h / Book.cpp// Book.h #ifndef BOOK_H #define BOOK_H #include string class Book { private: std::string isbn; std::string title; std::string author; bool isBorrowed; public: Book(const std::string i, const std::string t, const std::string a); // Getter 和 Setter std::string getISBN() const { return isbn; } std::string getTitle() const { return title; } std::string getAuthor() const { return author; } bool getBorrowedStatus() const { return isBorrowed; } void setBorrowedStatus(bool status) { isBorrowed status; } // 显示书籍信息 void display() const; }; #endif // BOOK_H// Book.cpp #include Book.h #include iostream Book::Book(const std::string i, const std::string t, const std::string a) : isbn(i), title(t), author(a), isBorrowed(false) {} void Book::display() const { std::cout ISBN: isbn , Title: title , Author: author , Status: (isBorrowed ? Borrowed : Available) std::endl; }User.h / User.cpp// User.h #ifndef USER_H #define USER_H #include string #include vector class Book; // 前向声明 class User { private: std::string userId; std::string name; std::vectorstd::string borrowedBooks; // 存储借阅的图书ISBN public: User(const std::string id, const std::string n); std::string getUserID() const { return userId; } std::string getName() const { return name; } // 借书/还书操作 bool borrowBook(const std::string isbn); bool returnBook(const std::string isbn); // 显示用户信息及借阅记录 void display() const; const std::vectorstd::string getBorrowedBooks() const { return borrowedBooks; } }; #endif // USER_H// User.cpp #include User.h #include iostream #include algorithm // for std::find User::User(const std::string id, const std::string n) : userId(id), name(n) {} bool User::borrowBook(const std::string isbn) { // 检查是否已经借过这本书简单演示实际可能允许借多本相同ISBN的书 if (std::find(borrowedBooks.begin(), borrowedBooks.end(), isbn) ! borrowedBooks.end()) { std::cout User name has already borrowed book ISBN: isbn std::endl; return false; } borrowedBooks.push_back(isbn); return true; } bool User::returnBook(const std::string isbn) { auto it std::find(borrowedBooks.begin(), borrowedBooks.end(), isbn); if (it ! borrowedBooks.end()) { borrowedBooks.erase(it); return true; } std::cout User name did not borrow book ISBN: isbn std::endl; return false; } void User::display() const { std::cout User ID: userId , Name: name std::endl; std::cout Borrowed Books ( borrowedBooks.size() ): ; for (const auto isbn : borrowedBooks) { std::cout isbn ; } std::cout std::endl; }Library.h / Library.cpp// Library.h #ifndef LIBRARY_H #define LIBRARY_H #include map #include string #include vector #include Book.h #include User.h class Library { private: std::mapstd::string, Book* books; // ISBN - Book* std::mapstd::string, User* users; // UserID - User* // 辅助函数防止内存泄漏在析构函数和拷贝控制成员中需要 void clear(); void copyFrom(const Library other); public: Library(); Library(const Library other); // 拷贝构造函数 Library operator(const Library other); // 拷贝赋值运算符 ~Library(); // 析构函数 // 图书管理 bool addBook(const std::string isbn, const std::string title, const std::string author); bool removeBook(const std::string isbn); Book* findBook(const std::string isbn) const; // 用户管理 bool addUser(const std::string userId, const std::string name); bool removeUser(const std::string userId); User* findUser(const std::string userId) const; // 业务逻辑 bool borrowBook(const std::string userId, const std::string isbn); bool returnBook(const std::string userId, const std::string isbn); // 查询 void listAllBooks() const; void listAllUsers() const; void listBooksBorrowedByUser(const std::string userId) const; }; #endif // LIBRARY_H// Library.cpp #include Library.h #include iostream #include algorithm Library::Library() {} Library::~Library() { clear(); } Library::Library(const Library other) { copyFrom(other); } Library Library::operator(const Library other) { if (this ! other) { clear(); copyFrom(other); } return *this; } void Library::clear() { for (auto pair : books) delete pair.second; books.clear(); for (auto pair : users) delete pair.second; users.clear(); } void Library::copyFrom(const Library other) { for (const auto pair : other.books) { books[pair.first] new Book(*(pair.second)); // 深拷贝Book对象 } for (const auto pair : other.users) { // 注意User对象内部的borrowedBooks是vectorstring可以直接拷贝 users[pair.first] new User(*(pair.second)); // 深拷贝User对象 } } bool Library::addBook(const std::string isbn, const std::string title, const std::string author) { if (books.find(isbn) ! books.end()) { std::cout Book with ISBN isbn already exists. std::endl; return false; } books[isbn] new Book(isbn, title, author); return true; } bool Library::removeBook(const std::string isbn) { auto it books.find(isbn); if (it ! books.end()) { // 检查书是否被借出 if (it-second-getBorrowedStatus()) { std::cout Cannot remove book isbn , it is currently borrowed. std::endl; return false; } delete it-second; books.erase(it); return true; } std::cout Book with ISBN isbn not found. std::endl; return false; } Book* Library::findBook(const std::string isbn) const { auto it books.find(isbn); if (it ! books.end()) return it-second; return nullptr; } bool Library::addUser(const std::string userId, const std::string name) { if (users.find(userId) ! users.end()) { std::cout User with ID userId already exists. std::endl; return false; } users[userId] new User(userId, name); return true; } bool Library::removeUser(const std::string userId) { auto it users.find(userId); if (it ! users.end()) { // 检查用户是否还有未还的书 if (!it-second-getBorrowedBooks().empty()) { std::cout Cannot remove user userId , they have borrowed books. std::endl; return false; } delete it-second; users.erase(it); return true; } std::cout User with ID userId not found. std::endl; return false; } User* Library::findUser(const std::string userId) const { auto it users.find(userId); if (it ! users.end()) return it-second; return nullptr; } bool Library::borrowBook(const std::string userId, const std::string isbn) { User* user findUser(userId); Book* book findBook(isbn); if (!user || !book) { std::cout User or Book not found. std::endl; return false; } if (book-getBorrowedStatus()) { std::cout Book isbn is already borrowed. std::endl; return false; } if (user-borrowBook(isbn)) { book-setBorrowedStatus(true); std::cout User userId successfully borrowed book isbn std::endl; return true; } return false; } bool Library::returnBook(const std::string userId, const std::string isbn) { User* user findUser(userId); Book* book findBook(isbn); if (!user || !book) { std::cout User or Book not found. std::endl; return false; } if (!book-getBorrowedStatus()) { std::cout Book isbn was not borrowed. std::endl; return false; } if (user-returnBook(isbn)) { book-setBorrowedStatus(false); std::cout User userId successfully returned book isbn std::endl; return true; } return false; } void Library::listAllBooks() const { std::cout All Books std::endl; for (const auto pair : books) { pair.second-display(); } } void Library::listAllUsers() const { std::cout All Users std::endl; for (const auto pair : users) { pair.second-display(); } } void Library::listBooksBorrowedByUser(const std::string userId) const { User* user findUser(userId); if (user) { std::cout Books borrowed by User userId : std::endl; const auto borrowedList user-getBorrowedBooks(); for (const auto isbn : borrowedList) { Book* book findBook(isbn); if (book) book-display(); } } else { std::cout User not found. std::endl; } }3.3 主函数测试与演示// main.cpp #include Library.h #include iostream int main() { Library lib; // 添加书籍和用户 lib.addBook(001, The C Programming Language, Bjarne Stroustrup); lib.addBook(002, Effective C, Scott Meyers); lib.addUser(U001, Alice); lib.addUser(U002, Bob); std::cout \nInitial State: std::endl; lib.listAllBooks(); lib.listAllUsers(); // 借书操作 std::cout \n--- Borrowing Books --- std::endl; lib.borrowBook(U001, 001); lib.borrowBook(U002, 002); // 尝试借已借出的书 lib.borrowBook(U001, 002); std::cout \nState after borrowing: std::endl; lib.listAllBooks(); lib.listBooksBorrowedByUser(U001); // 还书操作 std::cout \n--- Returning Books --- std::endl; lib.returnBook(U001, 001); std::cout \nFinal State: std::endl; lib.listAllBooks(); lib.listAllUsers(); // 测试删除有借阅记录时不能删 std::cout \n--- Testing Removal --- std::endl; lib.removeUser(U002); // Bob还有书没还应该失败 lib.returnBook(U002, 002); lib.removeUser(U002); // 现在应该成功 return 0; }4. 常见陷阱、调试技巧与性能考量即使理解了所有概念在实现面向对象程序时依然会踩到很多坑。这里总结一些高频问题和解决思路。4.1 内存管理泄漏、重复释放与悬空指针这是C新手和老手都会头疼的问题尤其是在自己管理动态内存时。内存泄漏new了但没有delete。在上面的Library类中我们必须在析构函数和拷贝赋值运算符中手动释放所有Book*和User*。排查工具在Linux/macOS下可以使用valgrind在Windows下可以使用Visual Studio的内存诊断工具或Dr. Memory。最佳实践尽可能使用智能指针std::unique_ptr,std::shared_ptr代替裸指针。例如Library中的map可以定义为std::mapstd::string, std::unique_ptrBook books;这样就不需要手动写析构函数来释放内存了极大地减少了出错概率。重复释放同一块内存被delete了两次。常发生在浅拷贝的情况下如前文的BadString例子或者多个指针指向同一对象其中一个指针delete后其他指针变成了“悬空指针”再次delete就会导致程序崩溃。解决方案遵循“Rule of Three/Five/Zero”。如果类需要管理资源如动态内存要么自己正确定义拷贝构造函数、拷贝赋值运算符和析构函数实现深拷贝或禁止拷贝要么使用智能指针将资源管理委托给库。悬空指针指针指向的内存已被释放但指针本身未被置空。后续解引用该指针会导致未定义行为通常崩溃。解决方案在delete一个指针后立即将其置为nullptr。在使用指针前检查其是否为nullptr。4.2 对象切片Object Slicing当派生类对象被赋值给基类对象而非指针或引用时会发生对象切片。派生类特有的部分会被“切掉”只保留基类的部分。class Base { public: int x; }; class Derived : public Base { public: int y; }; Derived d; d.x 1; d.y 2; Base b d; // 对象切片b只有xy丢失了。 Base ref d; // 正确引用多态有效 Base* ptr d; // 正确指针多态有效如何避免在需要多态性的地方始终使用基类的指针或引用。4.3 虚函数表与运行时多态开销虚函数通过虚函数表vtable实现这会带来一些开销空间开销每个包含虚函数的类对象会隐含一个指向vtable的指针vptr。时间开销通过指针或引用调用虚函数时需要一次间接寻址通过vptr找到vtable再找到函数地址。性能建议不要滥用虚函数。如果确定一个函数在派生类中不需要被重写就不要把它声明为virtual。对于小型、频繁调用的函数虚函数调用的开销可能变得显著。4.4 构造函数与析构函数中的虚函数在构造函数和析构函数中调用虚函数不会发生多态行为调用的是当前类正在构造或析构的类版本的函数。class Base { public: Base() { print(); } // 这里调用的是Base::print()不是Derived::print() virtual void print() { std::cout Base\n; } }; class Derived : public Base { public: virtual void print() override { std::cout Derived\n; } }; int main() { Derived d; // 输出 Base而不是 Derived }原因在构造派生类对象时基类部分先被构造此时对象的派生类部分还未初始化vptr指向的是基类的vtable。因此在基类构造函数中调用虚函数自然调用的是基类的版本。析构函数同理。4.5 使用现代C特性提升代码质量如果你使用的编译器支持C11及以上标准强烈建议使用现代C特性来编写更安全、更简洁的面向对象代码。智能指针用std::unique_ptr管理独占所有权的资源用std::shared_ptr管理共享所有权的资源。这可以消除绝大多数内存泄漏和重复释放的问题。override和final关键字在派生类中重写虚函数时使用override关键字让编译器检查是否真的重写了基类的虚函数避免因函数签名写错而意外创建新函数。使用final禁止类被进一步继承或虚函数被进一步重写。移动语义对于管理资源的类如我们的GoodString实现移动构造函数和移动赋值运算符可以大幅提升性能避免不必要的深拷贝。基于范围的for循环让遍历容器变得异常简洁。auto关键字简化复杂类型的声明但不要滥用在类型清晰或对可读性有帮助时才用。将现代C特性融入习题实践不仅能写出更健壮的代码也能让你更好地为实际项目开发做准备。面向对象程序设计不是孤立的语法学习而是一套解决问题的思想和方法论结合现代C的最佳实践才能发挥其最大的威力。