类继承

一、继承的基本概念

被继承的类称为基类或父类,继承的类称为派生类或子类。

就是子类从父类中得到成员的一个过程!

#include <iostream>
using namespace std;

class Father {
public: 
	int m_age;
	Father() {
		m_age=18;
		cout<<"use Father's func\n";
	}
	~Father() {
		cout<<"use Father's xigou\n";
	}
};
class Son:public Father {
public: 
	int m_xw;
	Son() {
		m_xw=99;
		cout<<"use Son's func\n";
	}
	~Son() {
		cout<<"use Son's xigou\n";
	}
};

int main() {
	Son s1;
	cout<<s1.m_age<<' '<<s1.m_xw<<'\n';
	return 0;
}

输出,也就是子类对象:

  1. 调用父类构造函数
  2. 调用子类构造函数
  3. 调用子类析构函数
  4. 调用父类析构函数
use Father's func
use Son's func
18 99
use Son's xigou
use Father's xigou

二、继承方式

不管继承方式如何,基类中的private成员在派生类中始终不能使用,也更没办法在类外去使用。

1. 三种访问权限

class Example {
public:      // 公有:类外可以访问
    int public_member;
    
protected:   // 保护:类外不能访问,但派生类可以访问
    int protected_member;
    
private:     // 私有:只能在本类中访问
    int private_member;
};

2. 三种继承方式

class Base {
public:
    int public_member;
protected:
    int protected_member;
private:
    int private_member;
};

// 公有继承
class DerivedPublic : public Base {
    // public_member 保持 public
    // protected_member 保持 protected
    // private_member 不可访问
};

// 保护继承
class DerivedProtected : protected Base {
    // public_member 变为 protected
    // protected_member 保持 protected
    // private_member 不可访问
};

// 私有继承
class DerivedPrivate : private Base {
    // public_member 变为 private
    // protected_member 变为 private
    // private_member 不可访问
};

3. 例子

在原始继承完了之后,可以用 using 去改变权限。

#include <iostream>         
using namespace std;        

class A {        // 基类
public:
    int m_a = 10;          // 公有成员
protected:
    int m_b = 20;          // 保护成员
private:
    int m_c = 30;          // 私有成员
};

class B : public A {       // 公有继承
public:
    using A::m_b;          // 把 m_b 的权限从 protected 改为 public
private:
    using A::m_a;          // 把 m_a 的权限从 public 改为 private
};

int main() {
    B b;   
    // b.m_a = 11;     // ❌ 错误:m_a 在 B 中变为 private,类外不能访问
    b.m_b = 21;          // ✅ 正确:m_b 被 using 改为 public,可以访问
    // b.m_c = 31;     // ❌ 错误:m_c 在 A 中是 private,派生类永远不能访问
}

三、类继承的对象模型

其实关于这个继承,我们完全可以把子类跟父类分开来,变成两个独立的类,只不过父类中有的成员子类中也有而已!

创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类构造函数。

四、名字遮蔽

就是从下到上,找到同名的就 over!

名字一样就好了!

当派生类定义了与基类同名的成员(变量或函数)时,派生类的成员会遮蔽基类的同名成员。

class Base {
public:
    void show() { cout << "Base::show()" << endl; }
};

class Derived : public Base {
public:
    void show() { cout << "Derived::show()" << endl; }  // 遮蔽了 Base::show()
};

int main() {
    Derived d;
    d.show();  // 输出:Derived::show(),而不是 Base::show()
    // 即使 Base::show() 存在,也被 Derived::show() 遮蔽了
}
class A { public: int x = 1; };
class B : public A { public: int x = 2; };  // 遮蔽 A::x
class C : public B { public: int x = 3; };  // 遮蔽 B::x

int main() {
    C obj;
    cout << obj.x << endl;    // 输出3,先在C中找到x
    cout << obj.B::x << endl; // 输出2,明确指定B的作用域
    cout << obj.A::x << endl; // 错误!不能直接访问A::x
    cout << obj.B::A::x << endl; // 输出1,通过B访问A
}

函数遮蔽 vs 函数重载

重要区别:函数在不在一块!
函数重载:在同一作用域中,函数名相同但参数不同
函数遮蔽:在不同作用域(基类和派生类)中,函数名相同(无论参数是否相同)

class Base {
public:
    void func() { cout << "Base::func()" << endl; }
    void func(int) { cout << "Base::func(int)" << endl; }  // 重载
};

class Derived : public Base {
public:
    void func() { cout << "Derived::func()" << endl; }  // 遮蔽了Base的所有func!
};

int main() {
    Derived d;
    d.func();     // ✅ 正确:调用Derived::func()
    // d.func(5); // ❌ 错误!Base::func(int)被遮蔽了
    
    // 必须显式指定作用域
    d.Base::func();    // ✅ 调用Base::func()
    d.Base::func(5);   // ✅ 调用Base::func(int)
}

解决

使用作用域解析符 ::

class A { public: void f() { } };
class B : public A { 
public: 
    void f() { }  // 遮蔽A::f()
    void test() {
        f();           // 调用B::f()
        A::f();        // 调用A::f()
    }
};

使用 using声明引入基类成员

class Base {
public:
    void func() { }
    void func(int) { }
};

class Derived : public Base {
public:
    using Base::func;  // 引入Base的所有func
    
    void func(double) { }  // 现在与Base::func构成重载
};

int main() {
    Derived d;
    d.func();      // ✅ 调用Base::func()
    d.func(5);     // ✅ 调用Base::func(int)
    d.func(3.14);  // ✅ 调用Derived::func(double)
}

继承的特殊关系

把基类看成动物,派生类看成猫、狗。

动物有的特征,猫、狗都会有!

1)如果继承方式是公有的,派生类对象可以使用基类成员。
2)可以把派生类对象赋值给基类对象(包括私有成员),但是,会舍弃非基类的成员。
3)基类指针可以在不进行显式转换的情况下指向派生类对象。(一个指向动物的指针,当然可以指向猫和狗啦)
4)基类引用可以在不进行显式转换的情况下引用派生类对象。(一个引用动物,当然也可以引用猫和狗)

基类指针或引用只能调用基类的方法,不能调用派生类的方法。因为它压根不知道有新东西!

posted @ 2026-02-19 20:44  FxorG  阅读(9)  评论(0)    收藏  举报