Part6 继承与OOD Inheritance and Object-Oriented Design(一)

  • 确定你的public继承塑模出 is-a关系
    这个论点只对public继承才成立,如Student和Person的关系,Student可以以public形式继承Person。而private继承的意义与此完全不同,至于protected继承,作者说“那是一种其意义至今仍然困惑我的东西”。
    is-a并非是唯一存在于classes之间的关系,另两个常见的关系是has-a和is-implemented-in-terms-of(根据某物实现出)。将上述这些重要的相互关系中的任何一个误塑为is-a而造成的错误设计,在c++中并不罕见,所以你应该确定这些clasess之间的相互关系。

  • 避免遮掩继承而来的名称 Avoid hiding inherited names
    这个题材和继承没有关系,而是和作用域Scopes有关。

int x;//global变量
void someFunc()
{
 double x; //local变量
  std::cin>>x; //读一个新值,这个值赋予的是local变量x
}

C++的名称遮掩规则所做的唯一事情就是:遮掩名称。至于名称是否应该相同或者是相同的类型,并不重要。本例中一个名为x的double遮掩了一个名为x的int。

class Base
{
private:
    int x;

public:
    virtual void mf1(){};
    virtual void mf1(int){};
    virtual void mf2(){};
    void mf3(){};
    void mf3(double){};
};


class Derived:public Base
{
public:
    virtual void mf1();
    void mf3();
    void mf4();
};


int _tmain(int argc, _TCHAR* argv[])
{
    Derived  d;
    int x = 3;
    d.mf1();
    d.mf1(3);//错误。。。因为Derived::mf1遮掩了Base::mf1
    d.mf2();//没问题,调用Base::mf2
    d.mf3();//没问题。调用Derived::mf3
    d.mf3(x);//错误。。。因为Derived::mf3遮掩了Base::mf3
}

如上述所见,即使base classes和Derived classes内的函数有不同的参数类型也使用,而且不论函数时Virtual或non-virtual一体使用。这和前面一开始展示的道理相同,当时函数someFunc内的double x遮掩了global作用域内的int x,如今Derived内的函数mf3遮掩了一个名为mf3但类型不同的base函数。

你可以使用using声明式达成目标:

class Base
{
private:
    int x;

public:
    virtual void mf1(){};
    virtual void mf1(int){};
    virtual void mf2(){};
    void mf3(){};
    void mf3(double){};
};


class Derived:public Base
{
public:
    using Base::mf1;//让base class内名为mf1和mf3的所有东西在Derived作用域内都可见并且是public
    using Base::mf3;
    virtual void mf1();
    void mf3();
    void mf4();
};


int _tmain(int argc, _TCHAR* argv[])
{
    Derived  d;
    int x = 3;
    d.mf1();
    d.mf1(3);//现在没问题,调用Base::mf1
    d.mf2();//没问题,调用Base::mf2
    d.mf3();//没问题。调用Derived::mf3
    d.mf3(x);//现在没问题,调用Base::mf3
}

这意味着如果你继承base class并加上重载函数,而你又希望重新定义或覆写其中一部分,那么你必须为那些原本会被遮掩的每一个名称引入一个using 声明,否则某些你希望继承的名称会被遮掩。
还有一种情况,如果只需要继承某些重载函数,可以使用转交函数的方式。

class Derived:public Base
{
public:
    virtual void mf1()
    {
    Base::mf1();
}
    void mf3();
    void mf4();
};

承和实现继承
pure virtual函数,simple(impure) virtual函数,non-virtual函数之间的差异,使你得以精确指定你想要Derived classes继承的东西:只继承接口(pure virtual),或是继承接口和一份缺省实现(Virtual函数),或是继承接口和一份强制实现(non-virtual)。由于这些不同类型的声明意味根本意义并不相同的事情,当你声明你的成员函数时,必须谨慎选择。

  • 绝不重新定义继承而来的non-virtual函数
  • Never redefine an inherited non-virtual function
    这种做法不是为了绕过编译器,而是为了保证代码的一致性。
    比如有如下代码:
class B{
public:
void mf();
};

class D: public B{};
虽然我们对B,D和mf一无所知,但面对一个类型为D的对象x:
D x;
由如下行为代码:
B * pB = &x;//获得一个指针指向x
pB->mf();//经由该指针调用mf
与如下代码的行为不一致:
D* pD = &x;
pD->mf();//经由该指针调用mf

我们希望或者期望“两者都通过对象x调用成员函数mf,由于两者所调用的函数都相同,凭借的对象也相同,所以行为也应该相同”。
如果mf是个Virtual函数,不论是通过pB或pD调用mf,都会导致调用D::mf,因为pB和pD真正指的都是一个类型为D的对象。

你可能感兴趣的:(Part6 继承与OOD Inheritance and Object-Oriented Design(一))