第18章 类的高级特性 友元 友元函数 友元函数是指可以访问类的私有成员和保护成员的非成员函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> class Box {private : double width; double height; double depth; public : Box (double w, double h, double d) : width (w), height (h), depth (d) {} friend double calculateVolume (const Box& box) ; friend void displayBox (const Box& box) ; }; double calculateVolume (const Box& box) { return box.width * box.height * box.depth; } void displayBox (const Box& box) { std::cout << "Width: " << box.width << std::endl; std::cout << "Height: " << box.height << std::endl; std::cout << "Depth: " << box.depth << std::endl; std::cout << "Volume: " << calculateVolume (box) << std::endl; } int main () { Box myBox (10.0 , 20.0 , 30.0 ) ; displayBox (myBox); return 0 ; }
友元类 一个类可以声明另一个类为友元,这样友元类的所有成员函数都可以访问原类的私有成员和保护成员。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> class Box {private : double width; double height; double depth; public : Box (double w, double h, double d) : width (w), height (h), depth (d) {} friend class BoxCalculator ; }; class BoxCalculator {public : double calculateVolume (const Box& box) { return box.width * box.height * box.depth; } double calculateSurfaceArea (const Box& box) { return 2 * (box.width * box.height + box.width * box.depth + box.height * box.depth); } void displayBoxInfo (const Box& box) { std::cout << "Width: " << box.width << std::endl; std::cout << "Height: " << box.height << std::endl; std::cout << "Depth: " << box.depth << std::endl; std::cout << "Volume: " << calculateVolume (box) << std::endl; std::cout << "Surface Area: " << calculateSurfaceArea (box) << std::endl; } }; int main () { Box myBox (10.0 , 20.0 , 30.0 ) ; BoxCalculator calculator; calculator.displayBoxInfo (myBox); return 0 ; }
成员函数作为友元 一个类的成员函数可以被声明为另一个类的友元。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <iostream> class Box ;class BoxCalculator {public : double calculateVolume (const Box& box) ; double calculateSurfaceArea (const Box& box) ; }; class Box {private : double width; double height; double depth; public : Box (double w, double h, double d) : width (w), height (h), depth (d) {} friend double BoxCalculator::calculateVolume (const Box& box) ; friend double BoxCalculator::calculateSurfaceArea (const Box& box) ; void display () { std::cout << "Width: " << width << std::endl; std::cout << "Height: " << height << std::endl; std::cout << "Depth: " << depth << std::endl; } }; double BoxCalculator::calculateVolume (const Box& box) { return box.width * box.height * box.depth; } double BoxCalculator::calculateSurfaceArea (const Box& box) { return 2 * (box.width * box.height + box.width * box.depth + box.height * box.depth); } int main () { Box myBox (10.0 , 20.0 , 30.0 ) ; BoxCalculator calculator; myBox.display (); std::cout << "Volume: " << calculator.calculateVolume (myBox) << std::endl; std::cout << "Surface Area: " << calculator.calculateSurfaceArea (myBox) << std::endl; return 0 ; }
类的静态成员 静态成员变量 静态成员变量是类的所有对象共享的变量,不属于任何单个对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <iostream> class Counter {private : static int count; int id; public : Counter () { id = ++count; } int getID () const { return id; } static int getCount () { return count; } }; int Counter::count = 0 ;int main () { std::cout << "Initial count: " << Counter::getCount () << std::endl; Counter c1; std::cout << "c1 ID: " << c1. getID () << std::endl; std::cout << "Count after c1: " << Counter::getCount () << std::endl; Counter c2; std::cout << "c2 ID: " << c2. getID () << std::endl; std::cout << "Count after c2: " << Counter::getCount () << std::endl; Counter c3; std::cout << "c3 ID: " << c3. getID () << std::endl; std::cout << "Count after c3: " << Counter::getCount () << std::endl; return 0 ; }
静态成员函数 静态成员函数属于类而不是对象,可以在没有对象的情况下调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <iostream> #include <string> class Student {private : std::string name; int id; static int nextID; public : Student (const std::string& n) : name (n), id (nextID++) {} void display () const { std::cout << "Name: " << name << ", ID: " << id << std::endl; } static int getNextID () { return nextID; } static void resetID () { nextID = 1 ; } }; int Student::nextID = 1 ;int main () { std::cout << "Next ID before creating students: " << Student::getNextID () << std::endl; Student s1 ("Alice" ) ; s1. display (); Student s2 ("Bob" ) ; s2. display (); Student s3 ("Charlie" ) ; s3. display (); std::cout << "Next ID after creating students: " << Student::getNextID () << std::endl; Student::resetID (); std::cout << "Next ID after reset: " << Student::getNextID () << std::endl; Student s4 ("David" ) ; s4. display (); return 0 ; }
类的常量成员 常量成员变量 常量成员变量必须在构造函数的初始化列表中初始化,且在对象的生命周期内不能改变。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> class Circle {private : const double PI; double radius; public : Circle (double r) : PI (3.14159 ), radius (r) {} double getArea () const { return PI * radius * radius; } double getCircumference () const { return 2 * PI * radius; } void setRadius (double r) { radius = r; } double getRadius () const { return radius; } }; int main () { Circle c (5.0 ) ; std::cout << "Radius: " << c.getRadius () << std::endl; std::cout << "Area: " << c.getArea () << std::endl; std::cout << "Circumference: " << c.getCircumference () << std::endl; c.setRadius (10.0 ); std::cout << "\nAfter changing radius: " << std::endl; std::cout << "Radius: " << c.getRadius () << std::endl; std::cout << "Area: " << c.getArea () << std::endl; std::cout << "Circumference: " << c.getCircumference () << std::endl; return 0 ; }
常量成员函数 常量成员函数承诺不会修改对象的状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <iostream> #include <string> class Person {private : std::string name; int age; public : Person (const std::string& n, int a) : name (n), age (a) {} void display () const { std::cout << "Name: " << name << ", Age: " << age << std::endl; } void setName (const std::string& n) { name = n; } void setAge (int a) { age = a; } std::string getName () const { return name; } int getAge () const { return age; } }; int main () { Person p1 ("Alice" , 30 ) ; p1. display (); p1. setName ("Bob" ); p1. setAge (25 ); p1. display (); const Person p2 ("Charlie" , 35 ) ; p2. display (); std::cout << "p2's name: " << p2. getName () << std::endl; std::cout << "p2's age: " << p2. getAge () << std::endl; return 0 ; }
类的类型转换 转换构造函数 转换构造函数是一个参数的构造函数,用于将其他类型转换为类类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <iostream> #include <string> class Distance {private : double meters; public : Distance () : meters (0 ) {} Distance (double m) : meters (m) { std::cout << "Conversion constructor called" << std::endl; } explicit Distance (int km) : meters(km * 1000 ) { std::cout << "Explicit conversion constructor called" << std::endl; } double getMeters () const { return meters; } void display () const { std::cout << "Distance: " << meters << " meters" << std::endl; } }; void printDistance (Distance d) { d.display (); } int main () { Distance d1; d1. display (); Distance d2 (100.5 ) ; d2. display (); Distance d3 = 200.75 ; d3. display (); printDistance (300.25 ); Distance d4 = Distance (5 ); d4. display (); return 0 ; }
类型转换运算符 类型转换运算符用于将类类型转换为其他类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <iostream> class Temperature {private : double celsius; public : Temperature (double c) : celsius (c) {} double getCelsius () const { return celsius; } operator double () const { return celsius * 9.0 / 5.0 + 32.0 ; } explicit operator bool () const { return celsius > 0 ; } }; int main () { Temperature t (25.0 ) ; std::cout << "Celsius: " << t.getCelsius () << std::endl; double fahrenheit = t; std::cout << "Fahrenheit: " << fahrenheit << std::endl; if (static_cast <bool >(t)) { std::cout << "Temperature is above freezing" << std::endl; } else { std::cout << "Temperature is at or below freezing" << std::endl; } Temperature t2 (-5.0 ) ; std::cout << "\nCelsius: " << t2. getCelsius () << std::endl; fahrenheit = t2; std::cout << "Fahrenheit: " << fahrenheit << std::endl; if (static_cast <bool >(t2)) { std::cout << "Temperature is above freezing" << std::endl; } else { std::cout << "Temperature is at or below freezing" << std::endl; } return 0 ; }
类的嵌套和局部类 嵌套类 嵌套类是在另一个类的内部定义的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 #include <iostream> #include <vector> class Stack {private : class Node { public : int data; Node* next; Node (int d, Node* n = nullptr ) : data (d), next (n) {} }; Node* top; int size; public : Stack () : top (nullptr ), size (0 ) {} ~Stack () { while (!isEmpty ()) { pop (); } } void push (int value) { top = new Node (value, top); size++; } int pop () { if (isEmpty ()) { throw std::runtime_error ("Stack underflow" ); } int value = top->data; Node* temp = top; top = top->next; delete temp; size--; return value; } int peek () const { if (isEmpty ()) { throw std::runtime_error ("Stack is empty" ); } return top->data; } bool isEmpty () const { return top == nullptr ; } int getSize () const { return size; } void display () const { if (isEmpty ()) { std::cout << "Stack is empty" << std::endl; return ; } std::cout << "Stack contents (top to bottom): " << std::endl; Node* current = top; while (current != nullptr ) { std::cout << current->data << " " ; current = current->next; } std::cout << std::endl; } }; int main () { Stack s; s.push (10 ); s.push (20 ); s.push (30 ); s.push (40 ); std::cout << "Stack size: " << s.getSize () << std::endl; s.display (); std::cout << "Top element: " << s.peek () << std::endl; std::cout << "Popped: " << s.pop () << std::endl; std::cout << "Popped: " << s.pop () << std::endl; std::cout << "Stack size after pops: " << s.getSize () << std::endl; s.display (); s.push (50 ); s.push (60 ); std::cout << "Stack size after pushes: " << s.getSize () << std::endl; s.display (); return 0 ; }
局部类 局部类是在函数内部定义的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <iostream> #include <vector> void processNumbers (const std::vector<int >& numbers) { class Result { private : int sum; double average; int min; int max; public : Result (const std::vector<int >& nums) { if (nums.empty ()) { sum = 0 ; average = 0 ; min = 0 ; max = 0 ; return ; } sum = 0 ; min = nums[0 ]; max = nums[0 ]; for (int num : nums) { sum += num; if (num < min) min = num; if (num > max) max = num; } average = static_cast <double >(sum) / nums.size (); } void display () const { std::cout << "Sum: " << sum << std::endl; std::cout << "Average: " << average << std::endl; std::cout << "Minimum: " << min << std::endl; std::cout << "Maximum: " << max << std::endl; } }; Result result (numbers) ; result.display (); } int main () { std::vector<int > nums = {10 , 20 , 30 , 40 , 50 }; std::cout << "Processing numbers: 10, 20, 30, 40, 50" << std::endl; processNumbers (nums); std::vector<int > emptyNums; std::cout << "\nProcessing empty vector" << std::endl; processNumbers (emptyNums); return 0 ; }
类的模板 类模板的基本概念 类模板允许我们创建通用的类,能够处理不同类型的数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <iostream> template <typename T> class Box {private : T value; public : Box (T v) : value (v) {} T getValue () const { return value; } void setValue (T v) { value = v; } void display () const { std::cout << "Value: " << value << std::endl; } }; int main () { Box<int > intBox (100 ) ; intBox.display (); Box<double > doubleBox (3.14 ) ; doubleBox.display (); Box<std::string> stringBox ("Hello" ) ; stringBox.display (); intBox.setValue (200 ); intBox.display (); doubleBox.setValue (6.28 ); doubleBox.display (); stringBox.setValue ("World" ); stringBox.display (); return 0 ; }
类模板的特化 类模板特化允许我们为特定类型提供自定义实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <iostream> #include <string> template <typename T> class Storage {private : T value; public : Storage (T v) : value (v) {} void display () const { std::cout << "Generic Storage: " << value << std::endl; } }; template <> class Storage <bool > {private : bool value; public : Storage (bool v) : value (v) {} void display () const { std::cout << "Boolean Storage: " << (value ? "true" : "false" ) << std::endl; } }; template <> class Storage <std::string> {private : std::string value; public : Storage (const std::string& v) : value (v) {} void display () const { std::cout << "String Storage: '" << value << "'" << std::endl; std::cout << "Length: " << value.length () << std::endl; } }; int main () { Storage<int > intStorage (42 ) ; intStorage.display (); Storage<double > doubleStorage (3.14 ) ; doubleStorage.display (); Storage<bool > boolStorage (true ) ; boolStorage.display (); Storage<std::string> stringStorage ("Hello, C++" ) ; stringStorage.display (); return 0 ; }
类的继承和多态高级特性 虚析构函数 虚析构函数确保在删除指向派生类对象的基类指针时,能够正确调用派生类的析构函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <iostream> class Base {public : Base () { std::cout << "Base constructor called" << std::endl; } virtual ~Base () { std::cout << "Base destructor called" << std::endl; } virtual void display () { std::cout << "Base display" << std::endl; } }; class Derived : public Base {private : int * data; public : Derived (int value) { std::cout << "Derived constructor called" << std::endl; data = new int (value); } ~Derived () { std::cout << "Derived destructor called" << std::endl; delete data; } void display () override { std::cout << "Derived display, value: " << *data << std::endl; } }; int main () { Base* ptr = new Derived (42 ); ptr->display (); delete ptr; return 0 ; }
纯虚函数和抽象类 纯虚函数是没有实现的虚函数,包含纯虚函数的类是抽象类,不能实例化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #include <iostream> #include <string> class Shape {public : virtual ~Shape () {} virtual double calculateArea () const = 0 ; virtual double calculatePerimeter () const = 0 ; virtual void display () const = 0 ; }; class Circle : public Shape {private : double radius; public : Circle (double r) : radius (r) {} double calculateArea () const override { return 3.14159 * radius * radius; } double calculatePerimeter () const override { return 2 * 3.14159 * radius; } void display () const override { std::cout << "Circle - Radius: " << radius << std::endl; std::cout << "Area: " << calculateArea () << std::endl; std::cout << "Perimeter: " << calculatePerimeter () << std::endl; } }; class Rectangle : public Shape {private : double width; double height; public : Rectangle (double w, double h) : width (w), height (h) {} double calculateArea () const override { return width * height; } double calculatePerimeter () const override { return 2 * (width + height); } void display () const override { std::cout << "Rectangle - Width: " << width << ", Height: " << height << std::endl; std::cout << "Area: " << calculateArea () << std::endl; std::cout << "Perimeter: " << calculatePerimeter () << std::endl; } }; int main () { Shape* shapes[2 ]; shapes[0 ] = new Circle (5.0 ); shapes[1 ] = new Rectangle (4.0 , 6.0 ); for (int i = 0 ; i < 2 ; i++) { shapes[i]->display (); std::cout << std::endl; } for (int i = 0 ; i < 2 ; i++) { delete shapes[i]; } return 0 ; }
虚函数和多态 虚函数允许派生类重写基类的方法,实现多态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 #include <iostream> #include <string> class Animal {protected : std::string name; public : Animal (const std::string& n) : name (n) {} virtual ~Animal () { std::cout << "Animal destructor called" << std::endl; } virtual void makeSound () { std::cout << "Animal makes a sound" << std::endl; } virtual void eat () { std::cout << "Animal eats" << std::endl; } void sleep () { std::cout << "Animal sleeps" << std::endl; } }; class Dog : public Animal {public : Dog (const std::string& n) : Animal (n) {} ~Dog () { std::cout << "Dog destructor called" << std::endl; } void makeSound () override { std::cout << name << " barks: Woof! Woof!" << std::endl; } void eat () override { std::cout << name << " eats bones" << std::endl; } }; class Cat : public Animal {public : Cat (const std::string& n) : Animal (n) {} ~Cat () { std::cout << "Cat destructor called" << std::endl; } void makeSound () override { std::cout << name << " meows: Meow! Meow!" << std::endl; } void eat () override { std::cout << name << " eats fish" << std::endl; } }; int main () { Animal* animals[2 ]; animals[0 ] = new Dog ("Buddy" ); animals[1 ] = new Cat ("Whiskers" ); for (int i = 0 ; i < 2 ; i++) { animals[i]->makeSound (); animals[i]->eat (); animals[i]->sleep (); std::cout << std::endl; } for (int i = 0 ; i < 2 ; i++) { delete animals[i]; } return 0 ; }
类的设计原则 封装 封装是将数据和操作数据的方法组合在一起,对外部隐藏实现细节。
继承 继承允许我们创建基于现有类的新类,重用代码并扩展功能。
多态 多态允许我们使用基类指针或引用指向派生类对象,调用派生类的方法。
抽象 抽象是通过抽象类和纯虚函数,定义接口而不提供实现。
组合 组合是将一个类的对象作为另一个类的成员,实现代码重用。
聚合 聚合是一种特殊的组合,其中成员对象的生命周期独立于容器对象。
最小特权原则 只授予类和函数必要的访问权限,避免不必要的暴露。
单一职责原则 一个类应该只有一个引起它变化的原因,专注于单一功能。
开放/封闭原则 类应该对扩展开放,对修改封闭。
里氏替换原则 派生类应该可以替换其基类,而不破坏程序的正确性。
接口隔离原则 客户端不应该依赖它不使用的接口。
依赖倒置原则 高层模块不应该依赖低层模块,两者都应该依赖抽象。
总结 本章介绍了类的高级特性,包括:
友元 :友元函数、友元类和成员函数作为友元静态成员 :静态成员变量和静态成员函数常量成员 :常量成员变量和常量成员函数类型转换 :转换构造函数和类型转换运算符嵌套和局部类 :嵌套类和局部类的定义和使用类模板 :类模板的基本概念和特化继承和多态高级特性 :虚析构函数、纯虚函数和抽象类类的设计原则 :封装、继承、多态、抽象、组合、聚合等设计原则这些高级特性使C++的类更加灵活和强大,能够适应各种复杂的编程需求。通过合理使用这些特性,你可以设计出更加模块化、可维护和可扩展的代码。
类的高级特性是C++的重要组成部分,也是成为优秀C++程序员的必备知识。通过不断学习和实践,你会逐渐掌握这些特性的使用技巧,并能够设计出更加优雅和高效的类。