c++ 面向对象之封装、抽象、继承、多态
最近正在学习设计模式,所以总结一下c++为面向对象提供的一些语言特性。作为设计模式这个专栏的开篇。
封装
封装其实很容易理解,就是使用类(class)将很多属性封装起来。值得注意的是
- 三种访问权限
- public:可以类创建的实体访问
- protected:只允许子类及本类的成员函数访问
- private:只允许本类的成员函数访问
- 三种继承方式
- public 继承
- protected 继承
- private 继承
基类中 | 继承方式 | 子类中 |
---|---|---|
public | public继承 | public |
public | protected继承 | protected |
public | private继承 | private |
protected | public继承 | protected |
protected | protected继承 | protected |
protected | private继承 | private |
private | public继承 | 子类无权访问 |
private | protected继承 | 子类无权访问 |
private | private继承 | 子类无权访问 |
由以上组合结果可以看出
1、public继承不改变基类成员的访问权限
2、private继承使得基类所有成员在子类中的访问权限变为private
3、protected继承将基类中public成员变为子类的protected成员,其它成员的访问 权限不变。
4、基类中的private成员不受继承方式的影响,子类永远无权访问。
此外,在使用private继承时,还存在另外一种机制:准许访问 。
我们已经知道,在基类以private方式被继承时,其public和protected成员在子类中变为private成员。然而某些情况下,需要在子类中将一个或多个继承的成员恢复其在基类中的访问权限。
C++支持以两种方式实现该目的
方法一,使用using 语句,这是C++标准建议使用的方式
方法二,使用访问声明,形式为 base-class::member;, 位置在子类中适当的访问声明处。(注,只能恢复原有访问权限,而不能提高或降低访问权限)
友元
友元严格来说是一种破坏封装的行为,友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend。
抽象
如果说封装的目的是为了隐藏属性和一些方法,那抽象就是为了隐藏暴露出的方法的具体实现。调用者只用关心类提供了哪些方法。严格来说抽象并不算是为了面向对象之后的产物,将实现封装在函数里就是对某个功能的抽象。
继承
继承的目的是为了函数复用,一般的使用场景是两个具有is-a关系的两个类之间。
因为c++中的派生类可以有多个基类,所以不可避免的会出现菱形继承的问题。
/间接基类A
class A{
protected:
int m_a;
};
//直接基类B
class B: public A{
protected:
int m_b;
};
//直接基类C
class C: public A{
protected:
int m_c;
};
//派生类D
class D: public B, public C{
public:
void seta(int a){ m_a = a; } //命名冲突
void setb(int b){ m_b = b; } //正确
void setc(int c){ m_c = c; } //正确
void setd(int d){ m_d = d; } //正确
private:
int m_d;
};
int main(){
D d;
return 0;
}
一个解决办法就是使用在子类中明确指定要使用哪个父类的属性
void seta(int a){ B::m_a = a; }
或者使用虚继承来解决
//间接基类A
class A{
protected:
int m_a;
};
//直接基类B
class B: virtual public A{ //虚继承
protected:
int m_b;
};
//直接基类C
class C: virtual public A{ //虚继承
protected:
int m_c;
};
//派生类D
class D: public B, public C{
public:
void seta(int a){ m_a = a; } //正确
void setb(int b){ m_b = b; } //正确
void setc(int c){ m_c = c; } //正确
void setd(int d){ m_d = d; } //正确
private:
int m_d;
};
int main(){
D d;
return 0;
}
多态
多态按字面的意思就是多种形态。
当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。
C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。
class A
{
public:
virtual void foo()
{
cout<<"A::foo() is called"<<endl;
}
};
class B:public A
{
public:
void foo()
{
cout<<"B::foo() is called"<<endl;
}
};
int main(void)
{
A *a = new B();
a->foo(); // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
return 0;
}
虚函数
virtual void foo()
{
cout<<"A::foo() is called"<<endl;
}
纯虚函数
virtual void foo()=0;
在C++中,要实现多态一定一定要使用基类类型的指针或者引用来指向子类对象,如果使用基础类型只会发生强转。