封装、继承和多态是C++语言面向对象设计的主要内容。
封装将函数和数据类型放到一个自定义类型中,特别是将函数放到自定义类型中,而C语言只是将内置数据类型放到自定义类型中,即结构体中,这是C语言和C++不同的。
继承和多态是和派生类以及虚函数向关联的。
继承有public继承,也有private和protected继承
私有继承的第一个规则:和公有继承相反,如果两个类之间的继承关系为私有,编译器一般不会将派生类对象转换成基类对象。第二个规则: 从私有基类继承而来的成员都成为了派生类的私有成员,即使它们在基类中是保护或公有成员。私有继承的含义:私有继承意味着 "用...来实现"。如果使类D私有继承于类B,这样做是因为你想利用类B中已经存在的某些代码,而不是因为类型B的对象和类型D的对象之间有什么概念上的关系。
私有继承后,基类所有成员在派生类中为private成员。看似没有任何意义,但私有继承可以帮助我们复用基类代码,并防止基类接口的曝光。因而,私有继承纯粹是一种实现技术。私有继承意味着只是继承实现,接口会被忽略。如果D私有继承于B,就是说D对象在实现中用到了B对象,仅此而已。私有继承在软件 "设计" 过程中毫无意义,只是在软件 "实现" 时才有用。
拿下面的这几个类为例:
没有一个派生类可以访问 B 的 private 部分。
在 D_priv 中,B 的 public 和 protected 部分是 private 的。在 D_prot 中,B 的 public 和 protected 部分是 protected 的。在 D_publ 中,B 的 public 部分是 public,protected 部分是 protected,因为 D_publ Is-AB。UserClass 仅可访问 B 的 public 部分,因为 B 对内部实现进行了封装。要让 B 的 public 方法在 D_priv 或 D_prot 中也是 public,需要使用 B:: 前缀,例:让 B::f(int, float) 方法在 D_prot 也是 public,应该写为:在C++中继承主要有三种关系:public、protected和private。这三种继承关系中public继承是最为常用的一种继承关系,private继承是最少见的继承关系。
1. public从语义角度上来说,public继承是一种接口继承,根据面向对象中的关系而言就是,派生类可以代替基类完成基类接口所声明的行为,也就是必须符合“Liskov替换原则(LSP)”,此时派生类可以自动转换成为基类的接口,完成接口转换。
从语法角度上来说,public继承会保留基类中成员(包括函数和变量等)的可见性不变,也就是说,基类的public成员为派生类的public成员,基类的protected成员为派生类的protected成员。2. protected从语义角度上来说,protected继承是一种实现继承,根据面向对象中的关系而言就是,派生类不能代替基类完成基类接口所声明的行为,也就是不符合“Liskov替换原则(LSP)”,此时派生类不能自动转换成为基类的接口,就算通过类型转换(static_cast和dynamic_cast)也会得到一个空指针。从语法角度上来说,protected继承会将基类中的public可见性的成员修改成为protected可见性,相当于在派生类中引入了protected成员,这样一来在派生类中同样还是可以调用基类的protected和public成员,派生类的派生类就也可以调用被protected继承的基类的protected和public成员。例如:
class CSample1 {
protected:
void printProtected() {}
public:
void printPublic() {}
};
class CSample2 : protected CSample1 {};
class CSample3 : public CSample2 {
void print3() {
printProtected();
printPublic();
}
};
3. private从语义角度上来说,private继承是一种实现继承,根据面向对象中的关系而言就是,派生类不能代替基类完成基类接口所声明的行为,也就是不符合“Liskov替换原则(LSP)”,此时派生类不能自动转换成为基类的接口,就算通过类型转换(static_cast和dynamic_cast)也会得到一个空指针。从语法角度上来说,private继承会将基类中的public和protected可见性的成员修改成为private可见性,这样一来虽然派生类中同样还是可以调用基类的protected和public成员,但是在派生类的派生类就不可以再调用被private继承的基类的成员了。
class CSample1 { protected:void printProtected() {}public:void printPublic() {}};class CSample2 : private CSample1 {};class CSample3 : public CSample2 { void print3() { printProtected(); // 编译错误,不可以调用该函数printPublic(); // 编译错误,不可以调用该函数}};
4. using声明
如果进行private或protected继承,则基类成员的访问级别在派生类中比在基类中更受限:
class Base{
public:
std::size_t size() const {return n;}
protected:
std::size_t n;
}
class Derived: private Base{...};
在这一继承层次中,size在Base中为public,但在Derived中为private。为了使size在Derived中成为public,可以在Derived的public部分增加一个using声明。如下这样改变Derived的定义,可以使size成员能够被用户访问,并使n能够被从Derived派生的类访问:
class Derived : private Base{
public:
using Base::size;
privated:
using Base::n;
//...
}
用struct和class保留字定义的类具有不同的默认访问级别。同样,默认继承访问级别根据使用哪个保留字定义派生类也不相同。使用class保留字定义的派生类默认具有private继承,而用struct保留字定义的类默认具有public继承:
class Base{}
struct D1 : Base{};//publicinheritance by default
classD2 : Base{};//private inheritance by default
有一种常见的误解认为用struct保留字定义的类与用class定义的类有更大的区别。实际上它们唯一的不同只是默认的成员保护级别和默认的派生保护级别(struct都为public,class都为private),除此之外,再也没有其他的区别。