您的位置:

C++继承:构建类层级结构的关键技术

一、继承的基本概念

继承是面向对象程序设计的基本特征之一。在C++语言中,继承允许我们定义一个新的类,这个新类继承已有的类的属性和行为,从而可以重复使用已有类的代码,避免代码冗余。

在C++中,通过在类定义中使用“:”符号,来指定一个类从另一个类继承而来。被继承的类称为基类,新定义的类称为派生类。派生类可以继承基类的公有成员、保护成员和私有成员,但只有公有成员能够被外部程序访问。

class BaseClass {
public:
    void publicFunc() { //公有函数
        std::cout << "BaseClass 的 publicFunc() 函数" << std::endl;
    }
protected:
    void protectedFunc() { // 保护函数
        std::cout << "BaseClass 的 protectedFunc() 函数" << std::endl;
    }
private:
    void privateFunc() { // 私有函数
        std::cout << "BaseClass 的 privateFunc() 函数" << std::endl;
    }
};

class DerivedClass : public BaseClass {
public:
    void callPublicFunc() {
        publicFunc(); // 从基类继承的公有函数
    }
    void callProtectedFunc() {
        protectedFunc(); // 从基类继承的保护函数
    }
   //void callPrivateFunc() { privateFunc(); }; 该语句会编译错误
};

int main() {
    DerivedClass obj; 
    obj.callPublicFunc(); //调用从基类继承而来的公有成员函数
    obj.callProtectedFunc(); //调用从基类继承而来的保护成员函数
    //obj.callPrivateFunc(); //编译错误,私有成员函数不能被访问
    return 0;
}

二、继承类型

在C++中,继承被分为三类:公有继承、保护继承和私有继承。

1.公有继承

公有继承是最常用的继承方式,它指定派生类能够继承基类的公有成员和保护成员。在公有继承中,基类的公有成员和保护成员在派生类中的访问权限不变。

class BaseClass {
public:
    void publicFunc() { 
        std::cout << "BaseClass 的公有函数" << std::endl;
    }
protected:
    void protectedFunc() { 
        std::cout << "BaseClass 的保护函数" << std::endl;
    }
};

class DerivedClass : public BaseClass {
    //从基类继承而来的公有成员和保护成员在DerivedClass中的访问权限不变
};

int main() {
    DerivedClass obj; 
    obj.publicFunc(); //从基类继承而来的公有成员函数可以在外部程序中被访问
    //obj.protectedFunc(); 非法,派生类外不能访问基类的保护成员
    return 0;
}

2.保护继承

保护继承与公有继承类似,不同之处在于基类的公有成员和保护成员在派生类中都成为保护成员,在派生类外部不能访问。只有派生类的成员函数或友元函数能够访问它们。

class BaseClass {
public:
    void publicFunc() { 
        std::cout << "BaseClass 的公有函数" << std::endl;
    }
protected:
    void protectedFunc() { 
        std::cout << "BaseClass 的保护函数" << std::endl;
    }
};

class DerivedClass : protected BaseClass {
    //从基类继承而来的公有成员和保护成员在DerivedClass中成为保护成员,其他程序不能访问
public:
    void callProtectedFunc() {
        protectedFunc(); //从基类继承而来的保护函数可以在派生类中被访问
    }
};

int main() {
    DerivedClass obj; 
    //obj.publicFunc(); 非法,从基类继承而来的公有成员在派生类外部不能访问
    //obj.protectedFunc(); 非法,从基类继承而来的保护成员在派生类外部不能访问
    obj.callProtectedFunc(); //从基类继承而来的保护函数可以在派生类中被访问
    return 0;
}

3.私有继承

私有继承意味着基类的公有和保护成员在派生类中均成为私有成员,只有派生类的成员函数或友元函数能够访问它们。私有继承不会带来新的接口。

class BaseClass {
public:
    void publicFunc() { 
        std::cout << "BaseClass 的公有函数" << std::endl;
    }
protected:
    void protectedFunc() { 
        std::cout << "BaseClass 的保护函数" << std::endl;
    }
};

class DerivedClass : private BaseClass {
    //从基类继承而来的公有成员和保护成员在DerivedClass中均为私有成员
public:
    void callProtectedFunc() {
        protectedFunc(); //从基类继承而来的保护函数可以在派生类中被访问
    }
};

int main() {
    DerivedClass obj; 
    //obj.publicFunc(); 非法,从基类继承而来的公有成员在派生类外部不能访问
    //obj.protectedFunc(); 非法,从基类继承而来的保护成员在派生类外部不能访问
    obj.callProtectedFunc(); //从基类继承而来的保护函数可以在派生类中被访问
    return 0;
}

三、构造函数和析构函数中的继承

在进行继承时,基类的构造函数和析构函数会被自动调用。

在构造派生类的对象时,首先会调用基类的默认构造函数,然后调用派生类的构造函数。当然,也可以在派生类的构造函数中显式调用基类的构造函数。考虑以下代码:

class BaseClass {
public:
    BaseClass() { //基类的默认构造函数
        std::cout << "BaseClass 的构造函数" << std::endl;
    }
    ~BaseClass() { //基类的析构函数
        std::cout << "BaseClass 的析构函数" << std::endl;
    }
};

class DerivedClass : public BaseClass {
public:
    DerivedClass() { //派生类的构造函数
        std::cout << "DerivedClass 的构造函数" << std::endl;
    }
    ~DerivedClass() { //派生类的析构函数
        std::cout << "DerivedClass 的析构函数" << std::endl;
    }
};

int main() {
    DerivedClass obj; //创建一个派生类的对象
    return 0;
}

执行上述代码,将输出以下结果:

BaseClass 的构造函数
DerivedClass 的构造函数
DerivedClass 的析构函数
BaseClass 的析构函数

在析构派生类的对象时,先调用派生类的析构函数,然后调用基类的析构函数。同样,也可以在派生类的析构函数中显式调用基类的析构函数。

四、虚函数和多态

虚函数是C++用于实现多态的重要机制。在基类中声明一个虚函数,派生类可以根据其需求重新定义这个虚函数,以实现多态性。在调用虚函数时,函数的实际调用取决于对象的类型,而不是指向该对象的指针或引用类型。例如:

class BaseClass {
public:
    virtual void virtualFunc() { 
        std::cout << "BaseClass 的虚函数" << std::endl;
    }
};

class DerivedClass : public BaseClass {
public:
    void virtualFunc() { //重定义基类的虚函数
        std::cout << "DerivedClass 的虚函数" << std::endl;
    }
};

int main() {
    DerivedClass obj; //创建一个派生类的对象
    BaseClass& ref = obj; //使用基类的引用来引用派生类的对象
    ref.virtualFunc(); //调用“引用的对象”的虚函数
    return 0;
}

以上代码中,我们声明了一个基类和一个派生类,基类中的虚函数被派生类重定义,使得它们的实现不同。在main函数中,创建了一个派生类对象,并用基类的引用来引用该对象,最后调用了该对象的虚函数。由于虚函数是根据对象类型而不是引用类型确定的,因此程序将调用派生类的虚函数,输出以下内容:

DerivedClass 的虚函数

五、抽象类

抽象类是具有至少一个纯虚函数的类,不能直接实例化,只能作为其他类的基类使用。纯虚函数没有函数体,只有函数原型。在基类中声明纯虚函数后,在派生类中必须定义该函数,否则将编译错误。

class AbstractClass { //抽象类
public:
    virtual void pureVirtualFunc() = 0; //纯虚函数
};

class DerivedClass : public AbstractClass {
public:
    void pureVirtualFunc() { 
        std::cout << "DerivedClass 实现了纯虚函数 pureVirtualFunc()" << std::endl;
    }
};

int main() {
    //AbstractClass obj; 非法,抽象类不能直接实例化
    DerivedClass obj; //创建一个派生类的对象
    AbstractClass& ref = obj; //使用基类的引用来引用派生类的对象
    ref.pureVirtualFunc(); //调用“引用的对象”的纯虚函数
    return 0;
}

在以上示例中,AbstractClass 是一个抽象类,定义了一个纯虚函数。派生类DerivedClass 定义了纯虚函数 pureVirtualFunc() 的实现,使得该派生类不再是抽象类。最后,创建了一个DerivedClass 对象,并用基类的引用来引用它,并调用了该对象的纯虚函数。

六、总结

在C++中,继承是构建类层级结构的关键技术之一。通过继承,我们可以重用已有的类的代码,提高程序的可维护性和可扩展性。C++中的继承有三种类型:公有继承、保护继承和私有继承。

C++中的构造函数和析构函数在进行继承时,会自动调用。虚函数和多态则是C++实现动态多态的重要机制。抽象类不能直接实例化,必须作为其他类的基类使用。

了解和掌握C++中的继承及相关特性,有助于我们构建更加复杂的类层级结构,提高