C++继承的问题 10
2016-06-22
继承是最为常用的一种继承关系,代表了接口继承含义,而他们分别具体滚行代表的含义如下:
1. public
从语义角度上来说,public继承是一种接口继承,根据面向对象中的关系而言就是,子类
可以代替父类完成父类接口所声明的行为,也就是必须符合“Liskov替换原则(LSP)”,
此时子类可以自动转换成为父类的接口,完成接口转换。
从语法角度上来说,public继承会保留父类中成员(包括函数和变量等)的可见性不变,
也就是说,如果父类中的某个函数是public的,那么在被子类继承后仍然是public的。
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(); // 编译错误,不可以调锋备帆用该函数
}
};
在面向对象的理论中有两种概念:接口、实现,所以就出现了所谓的接口继承和实现继
承两种关系。而protected和private就是实现继承中所要用到的,其实protected和private
两者则约束继承时并没有形成两种不同的继承类别,而仅仅只是为了方便C++类方法的传递
调用而设计的,其实在java这样面向对象要求更为严格的语言当中,没有实现继承,他必须
通过委托方式来完成这一概念,如果熟悉java就会明白,如果一个对象要使用另外一个对象
的接口功能,而自身又不能够充当该对象所扮演的角色时,就会通过委托来完成,这样一来
就必须在对象中包含一个委托对象,通过对象调用语法来完成功能;在C++中就可以通过
protected和private继承来完成java中的委托关系(当然C++也可以形成对象委托关系),
那么这种情况下protected继承就容许委托可以传递(也就是被多级子类调用),而private
继承是不容许委托被传递的。
2016-04-20 · 知道合伙人教育行家
class B{
protected:
string strWebSite;
public:
string& getWebSite(){return strWebSite;}
void setWebSite(string& strValue){strWebSite = strValue;}
};
class D: public B{
public:
string& getValue(){ return strWebSite;}
void setValue(string& strValue){ strWebSite = strValue;}
}
B是父类,拥有一个protected成员strWebSite;D是子类没有定义新的数据成员。如果我们定义一个D对象
D d;
B& rb = d;
D& rd = d;
rb.setWebSite("b string");
cout <<迹友 rb.getWebSite();
cout << rd.getValue();
二者输出相同,也就是“在父类中修改该成员变量以后,子类继承的该成员变量的值稿前发生相应变化”
rd.setValue("d string");
cout << rb.getWebSite();
cout << rd.getValue();
二者输出也相同,也就是你说的“反之也成立得情况”
这个保护类型的成员其实只是d对象中的一块内存,所以通过父类或子类引用访问的结果是姿敬槐一样的。
但是如果分别使用B和D两个类定义两个实例如:
B b1;
D d1;
则,b1和d1没有任何关系。
首先你一定要理解三种继承的区别,另外要清楚这里说的转举磨换是 指针类型 的转换。
这个问题要解释清楚比较复杂,我简单逐句使用实例给你演示说明一下。
类A{...};作为基类
1、 公有继承派生类B:public A{...}现在B具有A中public和protect属性了,定义A a 和B b,
public 继承,则用户代码和后代类都可以使用派生类到基类的转换:
A* c = &b 这是允许的,因为B是公有继承的A;但反之就不允许了,相信这个你是理解的
2、private 或 protected 继承派生的,则用户代码不能将派生类型对象转换为基类对象。
这句话也很容易理解,因为保护继承的话B:protect A{...},A中public元素在B中是protect的。
而类似的私有继承的所有元素都是燃配私有的,当然不允许指针转换了;
“如果是 private 继承,则从 private 继承类派生的类不能转换为基类。如果是 protected 继承,则后续派生类的成员可以转换为基类类型。”这两句要注意是指的继承类再次派生的子类,如下:
A{...}
B:protect A{}
C:public B{}这样继承B就作为C的基类了,C类中拥有A类中的所有属性,只不过A中public成员变成了protect成员了,但是作为子类仍然可以操作这个成员;
D:private A{}
E:public D{}这样继承E中其实是继承不到任何属于A中的元素的了,连访问成员都做不到更谈不到转正段斗换了
实际上就我个人感觉来说,问题中的用语是很不清晰的,因为毕竟是翻译过来的,我们学习的时候也没有必要总抱着一本书来学习,多读一些互相对照才能更准确的理解