相关文章:
从0开始C++(一):从C到C++
从0开始C++(二):类、对象、封装
从0开始C++(三):构造函数与析构函数详解
从0开始C++(四):作用域限定符、this指针、static与const关键字
从0开始C++(五):友元函数&运算符重载
从0开始C++(六):模板与容器的使用
目录
继承
派生类与基类构造函数的关系
委托构造
继承构造
多重继承
虚继承
继承
继承是一种面向对象的编程特性,允许一个类(称为子类或派生类)从另一个类(基类或父类)继承属性和方法。通过继承,子类可以获得基类的成员变量和成员函数,并且可以添加自己的特定实现。
C++中的继承有以下几种类型:
-
公有继承(public inheritance):在派生类中,基类的公有成员在派生类中仍然是公有的,基类的保护成员在派生类中变为保护的,基类的私有成员在派生类中不可访问。
-
保护继承(protected inheritance):在派生类中,基类的公有和保护成员在派生类中都变为保护的,基类的私有成员在派生类中不可访问。
-
私有继承(private inheritance):在派生类中,基类的公有和保护成员在派生类中都变为私有的,基类的私有成员在派生类中不可访问。
类内 | 派生类中 | 全局 | |
private | √ | × | × |
protected | √ | √ | × |
public | √ | √ | √ |
在使用继承时,可以使用关键字 public , protected 或 private 指定继承的类型。默认情况下,继承是公有的。
继承还可以用于实现多态性(polymorphism)。C++中的多态性允许通过基类的指针或引用来调用派生类的成员函数。这种特性可以方便地实现代码的重用和扩展。
下面是一个简单的C++继承的示例:
#include <iostream>
using namespace std;
class Animal {
public:
void eat() {
cout << "Animal is eating." << endl;
}
};
class Dog : public Animal {
public:
void bark() {
cout << "Dog is barking." << endl;
}
};
int main() {
Dog dog;
dog.eat(); // 继承自基类Animal的eat()函数
dog.bark(); // 子类Dog自己的函数
return 0;
}
输出结果为:
Animal is eating.
Dog is barking.
在上述示例中,Dog类继承自Animal类,并且可以调用Animal类中的成员函数eat(),同时还具有自己的成员函数bark()。
派生类与基类构造函数的关系
派生类和基类之间有一定的关系,包括构造函数。当创建派生类的对象时,首先会调用基类的构造函数,然后再调用派生类的构造函数。
派生类可以通过以下两种方式来调用基类的构造函数:
1、默认方式:如果在派生类的构造函数中没有显式调用基类的构造函数,则会默认调用基类的默认构造函数。如果基类没有默认构造函数,派生类的构造函数将无法编译通过。
class Base {
public:
Base() {
cout << "Base constructor" << endl;
}
};
class Derived : public Base {
public:
Derived() {
cout << "Derived constructor" << endl;
}
};
int main() {
Derived d;
return 0;
}
输出结果为:
Base constructor
Derived constructor
2、显式调用(透传构造):派生类的构造函数可以显式调用基类的构造函数,通过使用初始化列表来实现。
class Base {
public:
Base(int x) {
cout << "Base constructor with parameter: " << x << endl;
}
};
class Derived : public Base {
public:
Derived(int y) : Base(y) {
cout << "Derived constructor with parameter: " << y << endl;
}
};
int main() {
Derived d(10);
return 0;
}
输出结果为:
Base constructor with parameter: 10
Derived constructor with parameter: 10
需要注意的是,在派生类的构造函数中,应该按照继承层次从上到下调用基类的构造函数。并且每个构造函数只能直接调用其直接基类的构造函数,而不能调用其间接基类的构造函数。否则会导致编译错误。
另外,无论是默认方式还是显式调用,基类的构造函数都会在派生类的构造函数中被调用,以确保基类的成员变量和成员函数被正确初始化。
委托构造
C++11引入了委托构造的概念,允许一个构造函数直接调用另一个构造函数。委托构造函数可以简化代码并减少冗余。
使用委托构造函数的方式:
使用构造函数的初始化列表来调用其他构造函数。
class MyClass {
public:
MyClass(int x, int y) : a(x), b(y) {
// 其他初始化操作
}
MyClass(int x) : MyClass(x, 0) {
// 其他初始化操作
}
private:
int a;
int b;
};
在上述示例中,第一个构造函数接受两个参数,第二个构造函数只接受一个参数。通过在第二个构造函数的初始化列表中调用第一个构造函数,可以避免重复编写初始化操作。
需要注意的是,委托构造函数的调用顺序必须满足构造函数的初始化列表顺序,以确保对象的成员变量正确初始化。另外,委托构造函数不能形成递归调用,即构造函数之间不能形成循环委托。
继承构造
// 只加这一句,编译器就会自动添n个构造函数,Father为基类名称
using Father::Father;
实例
#include <iostream>
#include <map>
using namespace std;
// 基类
class Father
{
private:
string name;
public:
Father():name("张"){}
// 有参构造函数
Father(string name):name(name){}
string get_name()
{
return name;
}
};
// 派生类继承基类
class Son:public Father // public继承,权限保持不变
{
public:
// 只加这一句,编译器就会自动添加下面两种构造函数
using Father::Father;
// Son():Father(){}
// Son(string fn):Father(fn){}
};
int main()
{
// Son son;
Son son("王");
cout << son.get_name() << endl;
return 0;
}
多重继承
多重继承,即一个派生类可以同时继承多个基类。多重继承的语法形式如下:
class Derived : public Base1, public Base2, ... {
// 派生类的成员和函数
};
在上述示例中,Derived
是一个派生类,继承了Base1
和Base2
两个基类。通过逗号分隔,可以继承更多的基类。
派生类继承多个基类后,可以访问各个基类的成员变量和成员函数,以及自己定义的成员变量和成员函数。
当派生类中有与基类同名的成员时,可以通过作用域解析符::来指定要访问的成员属于哪个基类。
虚继承
另外,C++中还存在虚继承的概念。虚继承用于解决多重继承中的菱形继承问题(即一个派生类继承了多个共同的基类)以及相关的二义性问题。虚继承可以通过在基类之间添加 virtual 关键字来实现。具体的虚继承语法如下:
class Base1 {
// 基类1的成员
};
class Base2 {
// 基类2的成员
};
class Derived : public virtual Base1, public virtual Base2 {
// 派生类的成员
};
在虚继承中,派生类通过 virtual
关键字进行基类的声明,以确保只有一个实例的共同基类。这样就可以避免菱形继承和二义性问题。