继承的概念
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。
class Person
{
public:
void Print()
{
cout << "name:" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "peter";
int _age = 18;
private:
int _aa;
};
class Student :public Person
{
public:
void func()
{
_age = 10;
Print();
}
protected:
int _stuid;
};
int main()
{
Student s;
s.func();
s.Print();
return 0;
}
如上结果可以看到继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了Student复用了Person的成员。运行结果可以看出,在Student中可以调用Person中的函数,并且定义出的Student的对象中也可以直接使用Print函数。
继承定义
上面那段代码中,可以看到Student是Person的子类,继承的定义格式如下: 其中Student是子类的类名,public是继承方式,Person是父类也可以叫做基类。
class Student :public Person
继承方式和访问限定符
上面在定义子类继承的时候用到了public来修饰,实际上他和类里面的访问限定符一样,也可也使用protected和private。如下所示: 这里不同继承方式的子类,会继承父类里面不同访问限定符中的内容。 上面表格可以归结为如下几点:
- 基类的私有成员在子类中无论是以什么形式继承都是不可见的,这里的不可见的意思是虽然基类的私有成员还是继承到子类中,但是在语法上子类对象不管在类里面还是类外面都不能去访问这些私有成员
- 基类的私有对象在派生类中是不能被访问的,但是如果想做到成员不能在类外面被访问,但是可以在子类里面被访问,那可以使用访问限定符protected修饰,可以看出protected这个限定符主要可以用在继承上面。
- 上面的访问内容总的可以发现,除了基类的私有对象在任何子类中都不可见,基类的其他成员在子类的访问方式为成员在基类的访问限定符和子类的继承方式两者取其中权限更小的,权限大小顺序为public>protected>private
- 定义C++的类和结构体,C++的类是从结构体基础上发展来的,因此他们存在一定的区别,例如C++的类默认的访问限定符是private,结构体则是public,在继承方式上面也是一样类默认的继承方式是private,结构体则是public,但是一般在定义子类的继承时,最好显式的写出来。
- 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强。
测试代码如下:
class Person
{
public:
void Print()
{
cout << "name:" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "peter";
int _age = 18;
private:
int _aa;
};
class Student :public Person
{
public:
void func()
{
_age = 10;
Print();
}
protected:
int _stuid;
};
class Student1:protected Person
{
public:
void func()
{
_age = 10;
Print();
}
protected:
int _stuid;
};
class Student2 :private Person
{
public:
void func()
{
_age = 10;
Print();
}
protected:
int _stuid;
};
int main()
{
Student s;
s.func();
s.Print();
Student1 s1;
s1.func();
Student2 s2;
s2.func();
return 0;
}
上面的结构可以看到,protected和private继承方式继承来的内容可以在类里面使用,但是在类外面无法使用,即s1和s2定义出来的对象无法直接调用父类中的Print函数
切片
派生类对象可以赋值给基类的对象 / 基类的指针 / 基类的引用。这里有个形象的说法叫切片或者切割。寓意把派生类中父类那部分切来赋值过去。需要注意的是基类对象不能赋值给派生类对象,代码如下:
class Person
{
protected:
string _name;
string _sex;
int _age;
};
class Student : public Person
{
public:
int _No;
};
int main()
{
Person p;
Student s;
p = s;
Student* ptr = (Student*)&p;
Student& ref = (Student&)p;
Person* ptr = &s;
Person& ref = s;
return 0;
}
上面切片的代码可以形象的认为进行了如下的过程,子类中的内容比父类中多,将原本父类中的内容赋值给一个父类对象,可以形象的认为是将子类切片的过程。父类对象的指针或者引用实际上也可以赋值给子类的指针和引用,需要进行强制类型转换,但是这种做法可能会引起越界的风险。
|