1.继承
1.1.继承语法格式
要实现继承,遵循如下语法格式:
class SubClass : [public/protected/private] SuperClass
{
//...
};
其中SubClass
称为派生类或子类,SuperClass
称为基类或父类。
冒号之后的访问修饰符的作用如下:
- 1.
public
表示公有继承,基类的公有成员将成为派生类的共有成员,基类的私有部分也将成为派生类的一部分,但只能通过基类的公有方法和保护方法访问; - 2.
private
表示私有继承,基类的共有成员和保护成员将成为派生类的私有成员,这将意味着基类方法将不会成为派生类对象公有接口的一部分,但可以在派生类的成员函数中使用他们。 - 3.
protected
表示保护继承,它是私有继承的一个变体,基类的共有成员和保护成员将成为派生类的保护成员。
不管何种继承方式,基类的私有部分只能通过基类接口访问。
如果省略访问限定符,默认为private
继承。
如:
//student.h:
#include <string>
class Person
{
private:
int age;
std::string name;
public:
Person(int age = 0,std::string name="None");
~Person();
void show() const;
};
class Student : public Person
{
private:
double grade;
std::string schoolname;
public:
Student(int age = 0, std::string name = "None", double grade = 0.0, std::string schoolname = "None");
Student(const Person & person, double grade = 0.0, std::string schoolname = "None");
~Student();
void show() const;
void showSchoolName() const;//派生类添加方法
};
1.2.基类的构造函数能继承吗?
派生类可以继承到基类所有的公有部分和保护部分,但是构造函数除外。派生类不能继承基类的构造函数,同时,在创建派生类对象时,程序首先调用基类构造函数创建基类对象,再调用派生类构造函数。
正是由于这个原因,派生类的构造方法时,需要以成员初始化列表的方式将基类信息传递给基类构造函数,如我们定义Student
的构造函数时:
Student::Student(int age, std::string name, double grade, std::string schoolname) : Person(age,name)
{
std::cout << "Student::Student(int age, std::string name, double grade, std::string schoolname) call====" << std::endl;
this->schoolname = schoolname;
this->grade = grade;
}
如果省略成员初始化列表,那么当创建基类对象时,将使用默认基类构造函数,在这个构造函数中,可以省略成员初始列表,但在下一个构造函数中则不能省略了,如下:
Student::Student(const Person & person, double grade, std::string schoolname):Person(person)
{
std::cout << "Student::Student(const Person & person, double grade, std::string schoolname) call====" << std::endl;
this->schoolname = schoolname;
this->grade = grade;
}
在这个构造函数中,使用Person(person)
,因此将调用基类的拷贝构造函数,由于没有提供拷贝构造函数,因此编译器将提供默认的拷贝构造函数来完成赋值。
在类设计时,派生类构造函数主要用于初始化新增的数据成员,继承的数据成员由基类构造函数初始化。
1.3.类型兼容性原则
派生类和基类有如下5种特殊关系:
- 1.派生类对象可以使用基类的非私有方法;
- 2.基类指针可以直接指向派生类对象;
- 3.基类引用可以直接引用派生类对象;
- 4.基于3得,基类对象可以使用派生类对象进行初始化;
- 5.基于3得,派生类对象可以赋值给基类对象。
由于基类引用可以直接引用派生类对象,因此,当使用派生类对象初始化基类对象时:
Person p = s;
由于存在拷贝构造函数Person(const Person & p)
,从而可以得到第4点。
第5点也类似,由于存在隐式赋值运算符operator=(const Person &p )
,故可以使p引用派生类对象。
以上5点称为类型兼容性原则。
我们对上例中student.h
中声明的类进行实现,并通过这个例子来看看类型兼容性原则:
//student.cpp
#include <iostream>
#