子类继承父类的属性和方法

7 篇文章 0 订阅
2 篇文章 0 订阅

继承允许我们创建一个新的类(子类),它继承另一个类(父类)的属性和方法。这使得代码重用和扩展变得更加容易。

在Java中,子类可以继承父类的构造方法。当子类创建对象时,会自动调用父类的构造方法来初始化从父类继承的成员变量和方法。子类可以通过super关键字来调用父类的构造方法。

以下是一个示例代码:

public class Animal {
    private String name;

    public Animal(String name) {
        this.name = name;
    }

    public void speak() {
        System.out.println("Animal speaking");
    }
}

public class Dog extends Animal {
    private int age;

    public Dog(String name, int age) {
        super(name); // 调用父类的构造方法
        this.age = age;
    }

    public void speak() {
        System.out.println("Dog speaking");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Tommy", 3);
        dog.speak(); // 输出:Dog speaking
    }
}

在上面的例子中,Animal类有一个带有一个参数的构造方法,它接受一个name(名字)参数并将其赋值给name成员变量。Dog类继承Animal类,并新增了一个age(年龄)成员变量。Dog类的构造方法使用super关键字调用父类的构造方法来初始化name成员变量。最后,在Main类中创建Dog对象,输出结果为"Dog speaking"。

Python要让子类继承父类的所有方法和属性,包括含参数的__init__方法,可以使用super()函数来实现。

下面是一个示例代码:

class Parent:
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2
    
    def method1(self):
        print("Parent method1")
    
    def method2(self):
        print("Parent method2")


class Child(Parent):
    def __init__(self, arg1, arg2, arg3):
        super().__init__(arg1, arg2)  # 调用父类的__init__方法
        self.arg3 = arg3
    
    def method3(self):
        print("Child method3")


# 创建子类对象
child = Child("arg1 value", "arg2 value", "arg3 value")

# 调用继承的父类方法
child.method1()  # 输出:Parent method1
child.method2()  # 输出:Parent method2
child.method3()  # 输出:Child method3

在子类的__init__方法中使用super().__init__()调用父类的__init__方法,可以将父类的初始化代码复用。

在C++例子中,Cat类继承自Animal类,因此Cat对象可以调用eat方法(从Animal继承而来),同时也可以调用Speak方法(Cat类特有的)。

class Animal {  
public:  
    void eat() {  
        cout << "The animal eats." << endl;  
    }  
};  
  
class Cat : public Animal { // Dog继承自Animal  
public:  
    void Speak() {  
        cout << "喵!" << endl;  
    }  
};  
  
int main() {  
    Cat myCat;  
    myCat.eat(); // 继承自Animal的方法  
    myCat.Speak(); // Cat特有的方法  
    return 0;  
}
1 私有继承和公有继承

C++中类继承的两种主要方式,它们之间存在几个关键的区别:

  1. 成员访问权限:

    • 公有继承(public inheritance):在公有继承中,基类的公有(public)成员在派生类中仍然保持公有成员的地位。这意味着派生类的对象可以直接访问这些公有成员。同时,基类的保护(protected)成员在派生类中变为保护成员,即派生类的成员函数和友元可以访问它们,但派生类的对象不可以。基类的私有(private)成员在派生类中仍然是不可访问的。

    • 私有继承(private inheritance):在私有继承中,基类的公有和保护成员在派生类中都会变为私有成员。这意味着只有派生类的成员函数和友元可以访问这些成员,派生类的对象以及派生类之外的任何代码都不能直接访问它们。基类的私有成员在派生类中仍然是不可访问的。

  2. 用途和含义:

    • 公有继承:通常用于表示“是一种”(is-a)的关系。例如,如果有一个Animal类和一个从Animal公有继承的Dog类,那么可以说“一个狗是一种动物”。公有继承意味着派生类继承了基类的接口(即公有成员),并且派生类的对象可以像基类对象一样使用。

    • 私有继承:用于表示实现细节或者“拥有”(has-a)的关系。私有继承允许派生类使用基类的实现,但不需要暴露基类的接口给派生类的对象或外部代码。这通常用于实现代码复用,而不是创建新的接口。

  3. 多态行为:

    • 在公有继承中,如果基类有一个虚函数,并且派生类重写了这个函数,那么通过基类指针或引用调用这个函数时,会调用派生类的版本,实现运行时多态。

    • 在私有继承中,虽然派生类可以重写基类的虚函数,但由于基类成员在派生类中变为私有,外部代码无法通过基类指针或引用调用派生类的版本。因此,私有继承通常不用于实现多态行为

  4. 设计原则:

    • 使用公有继承时,应该仔细考虑是否确实需要继承基类的接口。如果派生类不需要暴露基类的所有公有成员,或者如果基类的公有成员与派生类的概念不符,那么使用公有继承可能不是最佳选择。

    • 使用私有继承时,应该明确这是为了代码复用而不是为了创建新的接口。私有继承通常

      2 关于虚继承(Virtual Inheritance)

      是C++中的一种机制,用于解决多重继承中可能出现的菱形继承问题。在菱形继承中,一个派生类从多个基类继承,而这些基类又共同继承自同一个更基础的类。如果没有使用虚继承,派生类中将包含多个基础类的子对象,这可能导致数据冗余、资源浪费以及歧义。

      用于实现细节,而不是用于定义类的外部行为。

      3 关于菱形继承

      菱形继承(Diamond Inheritance)是面向对象编程中一个常见的概念,特别是在C++中,它涉及到多重继承的复杂性。在菱形继承中,一个派生类从两个基类继承,而这两个基类又共同从一个更基础的类继承。这种结构形成了一个类似于菱形的继承关系图。

      下面是一个简单的例子来说明菱形继承:

      在这个例子中,MostDerived 类从 Derived1Derived2 两个类继承,而 Derived1Derived2 又都从 Base 类继承。因此,MostDerived 类实际上间接地从 Base 类继承了两次,形成了菱形继承。

      class Base {  
      public:  
          void foo() {  
              std::cout << "Base::foo()" << std::endl;  
          }  
      };  
        
      class Derived1 : public Base {  
      public:  
          // 可能有一些特有的成员函数或数据  
      };  
        
      class Derived2 : public Base {  
      public:  
          // 可能有一些特有的成员函数或数据  
      };  
        
      class MostDerived : public Derived1, public Derived2 {  
      public:  
          // MostDerived 类特有的成员函数或数据  
      };

      菱形继承可能会导致一些问题,特别是当涉及到虚函数和虚继承时。在上面的例子中,如果没有特别处理,MostDerived 类中将会有两个 Base 类的子对象(即 Derived1Derived2 各包含一个 Base 子对象),这可能导致资源重复和歧义。例如,如果 Base 类有一个数据成员,那么 MostDerived 类将有两个这样的数据成员,一个来自 Derived1,另一个来自 Derived2

      为了解决这个问题,C++提供了虚继承(Virtual Inheritance)的概念。通过在基类继承时使用 virtual 关键字,可以确保无论基类被继承多少次,在派生类中只会有一个基类子对象的实例。

      修改上面的例子以使用虚继承:

      在这个修改后的例子中,Derived1Derived2 都以虚方式从 Base 类继承,因此 MostDerived 类中只会有一个 Base 类的子对象实例,避免了资源重复和歧义。

      class Base {  
      public:  
          void foo() {  
              std::cout << "Base::foo()" << std::endl;  
          }  
      };  
        
      class Derived1 : virtual public Base { // 注意这里的 virtual 关键字  
      public:  
          // ...  
      };  
        
      class Derived2 : virtual public Base { // 注意这里的 virtual 关键字  
      public:  
          // ...  
      };  
        
      class MostDerived : public Derived1, public Derived2 {  
      public:  
          // ...  
      };

      使用虚继承需要谨慎,因为它可能引入额外的运行时开销,并可能使类的内存布局变得复杂。因此,只有在确实需要解决菱形继承问题时才应该使用虚继承。在大多数情况下,通过仔细设计类结构和使用组合而不是继承,可以避免菱形继承的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值