博客
关于我
c++中的10种常见继承
阅读量:366 次
发布时间:2019-03-05

本文共 8849 字,大约阅读时间需要 29 分钟。

C++继承的思想与实践

在C++编程中,继承是面向对象编程的核心概念之一。通过继承,一个新类可以基于已有的类(基类)继承其属性和方法,从而避免重复代码并增强代码的可维护性。本文将通过多个代码示例,探讨C++继承的不同方面及其常见错误。

1. 基本的继承与多态

以下代码展示了一个简单的基类及其派生类:

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()方法没有正确调用基类Baseprint()方法,导致无法正确显示基类属性。
  • 当使用Base::print()时,派生类的成员函数没有被正确隐藏,可能导致重复调用。

优化建议:

  • 在派生类的print()方法中,先调用基类的print()方法,然后显示派生类的属性。
  • 当使用b.Base::print()时,应确保派生类对象可以正确访问基类的成员。

2. 虚基类与多态

以下代码展示了使用虚基类实现多态的示例:

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(),确保正确实现多态。

3. 多级继承与纯虚函数

以下代码展示了多级继承及纯虚函数的应用:

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;}

错误分析:

  • CircleSquare类没有正确实现纯虚函数rotate(),导致无法实现多态。
  • 没有使用override关键字标记重写的虚函数,可能导致编译错误。

优化建议:

  • 在派生类中使用override关键字标记重写的虚函数。
  • 确保纯虚函数在派生类中被正确实现。

4. 私有继承与访问控制

以下代码展示了私有继承及访问控制的应用:

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()访问基类的成员函数。
  • 确保派生类的访问控制符合设计需求。

5. 多级继承与多态

以下代码展示了多级继承及多态的应用:

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类没有正确初始化radiusheight成员变量。

优化建议:

  • Cylinder类的构造函数中,确保正确初始化radiusheight
  • area()函数中,正确调用Circle::area()

6. protected访问控制属性

以下代码展示了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类的成员xy,但由于protected属性,无法直接访问。

优化建议:

  • 在派生类中使用Point::xPoint::y访问基类成员。
  • 确保访问控制符合设计需求。

7. 类的兼容性规则

以下代码展示了类的兼容性规则:

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有正确的构造函数。

8. 虚析构函数

以下代码展示了虚析构函数的应用:

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/

你可能感兴趣的文章
DP - Tickets - HDU - 1260
查看>>
Spring 与使用STOMP消息
查看>>
Java Swing JList:列表框组件
查看>>
jQuery中的动画
查看>>
1.2.3 项目、项目集、项目组合以及运营管理之间的关系
查看>>
【△重点△】LeetCode - 4. 寻找两个正序数组的中位数——二分查找
查看>>
LeetCode - 5. 最长回文子串——字符串、动态规划
查看>>
全局锁和表锁 :给表加个字段怎么有这么多阻碍?
查看>>
事务到底是隔离的还是不隔离的?
查看>>
@Import注解---导入资源
查看>>
二分查找与插入排序的结合使用
查看>>
892 三维形体的表面积(分析)
查看>>
40. 组合总和 II(dfs、set去重)
查看>>
16 最接近的三数之和(排序、双指针)
查看>>
279 完全平方数(bfs)
查看>>
410 分割数组的最大值(二分查找、动态规划)
查看>>
875 爱吃香蕉的珂珂(二分查找)
查看>>
桌面图标的自动排列图标
查看>>
第十一届蓝桥杯python组第二场省赛-数字三角形
查看>>
数字三角形的无返回值的深度优先搜索解法
查看>>