本文共 8849 字,大约阅读时间需要 29 分钟。
在C++编程中,继承是面向对象编程的核心概念之一。通过继承,一个新类可以基于已有的类(基类)继承其属性和方法,从而避免重复代码并增强代码的可维护性。本文将通过多个代码示例,探讨C++继承的不同方面及其常见错误。
以下代码展示了一个简单的基类及其派生类:
class Base {public: Base() {} Base(int i) : b_number(i) {} int get_number() { return b_number; } void print() { cout << b_number << endl; }};class Derived : public Base {private: int d_number;public: Derived(int i, int j) : Base(i), d_number(j) {} void print() { cout << get_number() << " "; cout << d_number << endl; }};int main() { Base a(2); Derived b(3, 4); cout << "a is "; a.print(); cout << "b is "; b.print(); cout << "base part of b is "; b.Base::print(); return 0;} 错误分析:
Derived中,print()方法没有正确调用基类Base的print()方法,导致无法正确显示基类属性。Base::print()时,派生类的成员函数没有被正确隐藏,可能导致重复调用。优化建议:
print()方法中,先调用基类的print()方法,然后显示派生类的属性。b.Base::print()时,应确保派生类对象可以正确访问基类的成员。以下代码展示了使用虚基类实现多态的示例:
class Thing {public: virtual void what_Am_I() { cout << "I am a Thing.\n"; } ~Thing() { cout << "Thing destructor\n"; }};class Animal : public Thing {public: virtual void what_Am_I() { cout << "I am an Animal.\n"; } ~Animal() { cout << "Animal destructor\n"; }};int main() { Thing *t = new Thing; Animal *x = new Animal; Thing *array[2] = {t, x}; for (int i = 0; i < 2; ++i) array[i]->what_Am_I(); delete[] array; return 0;} 错误分析:
virtual关键字标记what_Am_I()和析构函数,导致无法实现多态和内存泄漏。优化建议:
Thing中声明what_Am_I()和~Thing()为虚函数。Animal中重写what_Am_I()和~Animal(),确保正确实现多态。以下代码展示了多级继承及纯虚函数的应用:
class Figure {public: virtual void draw() = 0; virtual void rotate(double) = 0; Point &location() { return center; } void move(Point p) { center = p; } virtual ~Figure() {}};class Circle : public Figure {public: Circle(double r = 0, double x = 0, double y = 0) : Figure(x, y), radius(r) {} void draw() { cout << "A circle with center "; location().print(); cout << " and radius " << radius << endl; } void rotate(double) { cout << "no effect.\n"; } ~Circle() {}};class Square : public Figure {public: Square(double x = 0, double y = 0, double d = 0, double a = 0) : Figure(x, y), side(d), angle(a) {} void draw() { cout << "A square with center "; location().print(); cout << " side length " << side << "\n"; } void rotate(double a) { angle += a; cout << "The angle between one side and the X-axis is " << angle << endl; } ~Square() {}};int main() { Circle c(3); Square s(4, 5, 6); Figure *f = &c; f->draw(); f->move(Point(2, 2)); s.draw(); s.rotate(1); return 0;} 错误分析:
Circle和Square类没有正确实现纯虚函数rotate(),导致无法实现多态。override关键字标记重写的虚函数,可能导致编译错误。优化建议:
override关键字标记重写的虚函数。以下代码展示了私有继承及访问控制的应用:
class Base {private: int priv;protected: int prot;public: int publ; Base() {} Base(int a, int b, int c) : priv(a), prot(b), publ(c) {} int get_priv() { return priv; } int get_prot() { return prot; } int get_publ() { return publ; }};class Derived1 : private Base {public: Derived1(int a, int b, int c) : Base(a, b, c) {} int get1_priv() { return get_priv(); } int get1_prot() { return prot; } int get1_publ() { return publ; }};class Leaf1 : public Derived1 {public: Leaf1(int a, int b, int c) : Derived1(a, b, c) {} void print() { cout << "Leaf1 members: " << get1_priv() << " " << get1_prot() << " " << get1_publ() << endl; }};int main() { Derived1 d1(1, 2, 3); Leaf1 lf1(4, 5, 6); cout << lf1.get1_priv() << " " << lf1.get1_prot() << " " << lf1.get1_publ() << endl; return 0;} 错误分析:
Leaf1中,print()方法试图访问基类的get_priv()和get_prot()方法,但由于私有继承,不能直接访问。优化建议:
Base::get_priv()和Base::get_prot()访问基类的成员函数。以下代码展示了多级继承及多态的应用:
class Point {public: Point(double x = 0, double y = 0) { x = xval; y = yval; }protected: double x, y;};class Circle : public Point {public: Circle(double r = 0, double xval = 0, double yval = 0) : Point(xval, yval), radius(r) {} double area() { return 3.14159 * radius * radius; }protected: double radius;};class Cylinder : public Circle {public: Cylinder(double hv = 0, double rv = 0, double xv = 0, double yv = 0) : Circle(xv, yv, rv), height(hv) {} double area() { return 2.0 * Circle::area() + 2.0 * 3.14159 * radius * height; }protected: double height;};int main() { Point p(2, 3); Circle c(7, 6, 5); Cylinder cyl(10, 11, 12, 13); cout << p; cout << c; cout << "area of circle: " << c.area() << endl; cout << cyl; cout << "area of cylinder: " << cyl.area() << endl; return 0;} 错误分析:
Cylinder类的area()函数没有正确使用Circle::area(),导致错误。Cylinder类没有正确初始化radius和height成员变量。优化建议:
Cylinder类的构造函数中,确保正确初始化radius和height。area()函数中,正确调用Circle::area()。以下代码展示了protected访问控制属性的应用:
class Point {public: Point(double xval = 0, double yval = 0) { x = xval; y = yval; }public: void print() { cout << " Point:X:Y: " << x << "," << y << "/n"; }protected: double x, y;};class Circle : public Point {public: Circle(double r = 0, double xval = 0, double yval = 0) : Point(xval, yval), radius(r) {} void print() { cout << "Circle:radius:" << radius << endl; } double area() { return 3.14159 * radius * radius; }protected: double radius;};int main() { Point p(2, 3); Point pp = p; Circle c(7, 6, 5); cout << "Point P= " << p; cout << "Point PP= " << pp; cout << "Circle c= " << c; pp = c; cout << "Point PP= " << pp; pp = (Point)c; cout << "Point PP= " << pp; return 0;} 错误分析:
Circle类的print()方法试图访问Point类的成员x和y,但由于protected属性,无法直接访问。优化建议:
Point::x和Point::y访问基类成员。以下代码展示了类的兼容性规则:
class Base {public: void func() { cout << "Base class function.\n"; }};class Derived : public Base {public: void func() { cout << "Derived class function.\n"; }};void foo(Base b) { b.func(); }int main() { Derived d; Base b; Base *p = &d; Base br = d; b = d; b.func(); d.func(); p->func(); foo(d); br.func(); return 0;} 错误分析:
p->func()和br.func()没有问题,但b = d可能导致错误,因为Derived没有构造基类成员。优化建议:
Derived的构造函数中,确保正确初始化基类成员。b = d,除非Derived有正确的构造函数。以下代码展示了虚析构函数的应用:
class Base {private: int id; char *name;public: Base(int a = 0, char *s = "") : id(a) { if (!s) name = NULL; else { name = new char[strlen(s) + 1]; strcpy(name, s); } cout << "base default constructor\n"; } Base(const Base &b) : id(b.id) { if (!b.name) name = NULL; else { name = new char[strlen(b.name) + 1]; strcpy(name, b.name); } cout << "base copy constructor\n"; } ~Base() { if (name != NULL) delete[] name; cout << "base destructor\n"; } const Base &operator=(const Base &b) { if (this != &b) { id = b.id; delete[] name; if (!b.name) name = NULL; else { name = new char[strlen(b.name) + 1]; strcpy(name, b.name); } } cout << "base assignment operator\n"; return *this; } friend ostream &operator<<(ostream &out, const Base &b) { out << "Base member id = " << b.id << endl; out << "Base member name = " << b.name << endl; return out; }};class Derived : public Base {private: float f; char *label;public: Derived(int a = 0, char *s = "", float x = 0, char *t = "") : Base(a, s), f(x) { if (!t) label = NULL; else { label = new char[strlen(t) + 1]; strcpy(label, t); } cout << "derived default constructor\n"; } Derived(const Derived &d) : Base(d), f(d.f) { if (!d.label) label = NULL; else { label = new char[strlen(d.label) + 1]; strcpy(label, d.label); } cout << "derived copy constructor\n"; } ~Derived() { delete[] label; cout << "derived destructor\n"; } const Derived &operator=(const Derived &d) { if (this != &d) { Base::operator=(d); f = d.f; if (!d.label) label = NULL; else { label = new char[strlen(d.label) + 1]; strcpy(label, d.label); } } cout << "derived assignment operator\n"; return *this; } friend ostream &operator<<(ostream &out, const Derived &d) { out << (Base)d; out << "Derived member f = " << d.f << endl; out << "Derived member label = " << d.label << endl; return out; }};int main() { Derived d1; Derived d2(d1); return 0;} 错误分析:
Derived类的operator=方法没有正确初始化label成员,可能导致内存泄漏。override关键字标记重写的虚函数,导致编译错误。优化建议:
Derived的构造函数中,确保正确初始化label成员。override关键字标记重写的虚函数。label的内存释放。通过以上分析和优化,可以更好地理解C++继承的思想及其在实际编程中的应用。
转载地址:http://zquwz.baihongyu.com/