Fork me on GitHub

C++ 多态

11. 多态

11.1 Conversions

  • Public Inheritance should imply substitution
    • If B isa A, you can use a B anywhere an A can be used.
  • 示例:
#include <iostream>
using namespace std;

class A {
public:
        int i;
public:
        A():i(10) {}
};

class B: public A{
private:
        int j;
public:
        B():j(30){}
public:
        void f() { cout << "B.j = " << j << endl; }
};

int main()
{
    A a;
    B b;

    cout << a.i << " " << b.i << endl;

    cout << sizeof(a) << " " << sizeof(b) << endl;

    int *p = (int*)&a;

    cout << p << " " << *p << endl;

    *p = 20;

    cout << a.i << endl;

    p = (int*)&b;

    cout << p << " " << *p << endl;

    p++;
    *p = 50;
    b.f();

    return 0;
}

11.2 Upcasting(向上造型)

  • Upcasting is the act of converting from a Derived reference or pointer to a base class reference or pointer.

11.3 Polymorphism(多态)

  • 示例:
class XYPos{...};

class Shape{
public:
    Shape();
    virtual ~Shape();  // 析构函数
    virtual void render();
    void move(const XYPos&);
    virtual void resize();

protected:
    XYPos center;
};

class Ellipse : public Shape {
public:
    Ellipse(float maj, float minr);
    virtual void render();
protected:
    float major_axis, minor_axis;
};

class Circle : public Ellipse {
public:
    Circle(float radius) : Ellipse(radius, radius) {}
    virtual void render();
};

void render(Shape* p) {
    p->render;  // calls correct render function for given Shape!
}

void func() {
    Ellipse ell(10, 20);
    ell.render();
    Circle circ(40);
    circ.render();

    render(&ell);   // 调用 Ellipse 的 render
    render(&circ);  // 调用 Circle 的 render
}

11.3.1 多态特性

  • Upcast:take an object of the derived class as an object of the base one.
  • Dynamic binding:
    • Binding: which function to be called
      • Static binding: call the function as the code
      • Dynamic binding: call the function of the object

11.3.2 多态实现

  • 编译命令:g++ a.cpp -m32
#include <iostream>
using namespace std;

class A {
public:
    A() : i(10) {}
    virtual void f() { cout << "A::f() = " << i << endl; }
    int i;
};

int main()
{
    A a;
    A b;
    a.f();
    cout << sizeof(a) << endl;

    int *p = (int*)&a;
    int *q = (int*)&b;
    cout << *p << "  " << *q << endl;
    p++;
    cout << *p << endl;
    return 0;
}
  • 示例二:
#include <iostream>
using namespace std;

class A {
public:
    A() : i(10) {}
    virtual void f() { cout << "A::f() = " << i << endl; }
    int i;
};

class B: public A {
public:
    B() : j(20) {}
    virtual void f() { cout << "B::f() " << j << endl; }
    int j;
};

int main()
{
    A a;
    B b;
    
    A* p = &b;
    p->f();
    return 0;
}

11.3.3 Virtual destructors

  • Make destructors virtual if they might be inherited
Shape *p = new Ellipse(100.0F, 200.0F);

delete p;

// Want Ellipse::~Ellipse() to be called
// 1, Must declare Shape::~Shape() virtual
// 2, It will call Shape::~Shape() automatically
// If Shape::~Shape() is not virtual, only Shape::~Shape() will be invoked!

11.3.4 Overriding

  • Overriding redefines the body of a virtual function
class Base {
public:
    virtual void func();
};

class Derived : public Base {
public:
    virtual void func();
    // overrides Base::func()
}

// 子类中调用父类方法
void Derived::func() {
    cout << "In Derived::func!";
    Base::func();
}
  • 示例二:
class Expr {
public:
    virtual Expr* newExpr();
    virtual Expr& clone();
    virtual Expr self();
};

class BinaryExpr : public Expr {
public:
    virtual BinaryExpr* newExpr();  // OK
    virtual BinaryExpr& clone();  // OK
    virtual BinaryExpr self();  // Error!
}

11.3.5 Overloading and virtuals

  • Overloading adds multiple signatures
  • If you override an overloaded function, you must override all of the variants!
    • Can't override just one
    • If you don't override all, some will be hidden
class Base {
public:
    virtual void func();
    virtual void func(int);
};

参考资料:

posted @ 2022-06-16 14:11  小a的软件思考  阅读(28)  评论(0编辑  收藏  举报