做者:LogMsegmentfault
本文原载于 https://segmentfault.com/u/logm/articles,不容许转载~函数
class Person {...}; class Student : public Person {...}; void eat(const Person& p); void study(const Student& s); eat(p); // ok eat(s); // ok,Student能够视做Person调用函数 study(s); //ok study(p); //error,Person不能视做Student
int x; //global变量 void someFunc() { double x; //local变量 std::cin >> x; //local变量的x遮掩了global变量的x,实际起做用的是local变量的x }
//定义基类 class Base { private: int x; public: virtual void mf1() = 0; virtual void mf1(int); virtual void mf2(); void mf3(); void mf3(double); ... }; //定义派生类 class Derived : public Base { public: virtual void mf1(); void mf3(); void mf4(); ... }; //使用 Derived d; int x; ... d.mf1(); //ok,调用Derived::mf1 d.mf1(x); //bad,由于Derived::mf1遮掩了Base::mf1 d.mf2(); //ok,调用Base::mf2 d.mf3(); //ok,调用Derived::mf3 d.mf3(x); //bad,由于Derived::mf3遮掩了Base::mf3
//解决方法1 //定义派生类 class Derived : public Base { public: using Base::mf1; //让基类中名为mf1和mf3的全部东西在此做用域内可见 using Base::mf3; virtual void mf1(); void mf3(); void mf4(); ... }; //使用 Derived d; int x; ... d.mf1(); //ok,调用Derived::mf1 d.mf1(x); //ok,调用Base::mf1 d.mf2(); //ok,调用Base::mf2 d.mf3(); //ok,调用Derived::mf3 d.mf3(x); //ok,调用Base::mf3
//解决方法2 //定义基类 class Base { public: virtual void mf1() = 0; virtual void mf1(int); ... }; //定义派生类 class Derived : public Base { public: virtual void mf1() { Base::mf1(); } // 转交函数 ... }; //使用 Derived d; int x; ... d.mf1(); //ok,调用Derived::mf1 d.mf1(x); //bad,由于Base::mf1被遮掩,且Base::mf1(int)没有被转交
以下代码所示,有3类继承关系:this
class Shape { public: virtual void draw() const = 0; virtual void error(const std::string& msg); int objectID() const; ... }; class Rectangle : public Shape {...}; class Ellipse : public Shape {...};
//假设你正在写一个游戏软件,每一个游戏人物都应该有"健康"这个属性 class GameCharacter { public: virtual int healthValue() const; //返回游戏人物的健康状态 ... };
上面的写法没有问题,基类提供了接口和一个缺省的实现,派生类能够选择是否重写这个函数。可是,做者也提醒,还有一些其它的写法:设计
//方法1:借由Non-Virtual Interface(NVI)手法实现Template Method模式 class GameCharacter { public: int healthValue() const { ... //在开始主函数前,能够作一些额外的工做 int retVal = doHealthValue(); //这个函数能够被子函数重写 ... //在结束主函数后,能够作一些额外的工做 return retVal; } ... private: virtual int doHealthValue() const { ... } };
//方法2:借由函数指针实现Strategy模式 //这种方法容许同一个派生类的不一样对象使用不一样的函数计算健康状态 class GameCharacter { public: typedef int (*HealthCalcFunc)(const GameCharacter&); explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf) { } int healthValue const { return healthFunc(*this); } ... private: HealthCalcFunc healthFunc; };
//方法3:借由tr1::function完成Strategy模式 //这种方法比函数指针更自由,它能够是函数指针,也能够是任何能够被调用的东西 class GameCharacter { public: typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc; explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf) { } int healthValue const { return healthFunc(*this); } ... private: HealthCalcFunc healthFunc; }
//方法4:古典的Strategy模式 //HealthCalcFunc来自另外一个继承体系 class GameCharacter; class HealthCalcFunc { public: ... virtual int calc(const GameCharacter& gc) const {...} ... }; HealthCalcFunc defaultHealthCalc; class GameCharacter { public: explicit GameCharacter(HealthCalcFun* phcf = &defaultHealthCalc) : pHealthCalc(phcf) { } int healthValue() const { return pHealthCalc->calc(*this); } ... private: HealthCalcFunc* pHealthCalc; };
//基类 class B { public: void mf(); ... }; //派生类 class D { public: void mf(); //遮掩B::mf ... }; //使用 D x; B* pB = &d; //调用B::mf() pB->mf(); D* pD = &d; //调用D::mf() pD->mf(); //若是B::mf()是virtual函数,则上面两处都是调用D::mf() //因此也就能够解释,条款7所述的"使用多态时,基类的析构必须为virtual"
//基类 class Shape { public: enum ShapeColor {Red, Green, Blue}; virtual void draw(ShapeColor color=Red) const = 0; }; //派生类 class Rectangle : public Shape { public: virtual void draw(ShapeColor color=Green) const; ... }; //使用 Shape* pR = new Rectangle; //请注意类型是Shape* pR->draw(); //调用Rectangle::draw(Shape::Red),由于缺省值是在编译期间静态绑定的,而pR的静态类型为Shape*,是基类
//基类 class Shape { public: enum ShapeColor {Red, Green, Blue}; void draw(ShapeColor color=Red) const { doDraw(color); } ... private: virtual void doDraw(ShapeColor color) const = 0; }; //派生类 class Rectangle : public Shape { public: ... private: virtual void doDraw(ShapeColor color) const { ... } ... };
class Address {...}; class PhoneNumber {...}; class Person { public: ... private: std::string name; Address address; PhoneNumber voiceNumber; PhoneNumber faxNumber; };
class Person {...}; class Student : private Person {...}; void eat(const Person& p); Person p; Student s; eat(p); //ok eat(s); //bad,Student不能被视为Person