[PYTHON] L'histoire selon laquelle le comportement d'héritage est assez différent dans chaque langue

introduction

Cet article est une compilation des résultats de mes recherches sur les valeurs réellement générées en écrivant l'héritage de classe dans différentes langues de la même manière. Parfois, je travaillais dur depuis Hello World, pensant qu'il y avait une telle grammaire même dans une langue connue.

Qui gagnerait à ce que ce soit difficile à assembler? Cependant, je laisserai cela à ceux qui s'intéressent à la même chose. Non, il peut y avoir de nouvelles découvertes, alors veuillez le lire pour le moment. Cela a peut-être été un résultat étonnamment intéressant.

Langue examinée

Code utilisé dans l'enquête

Une classe enfant hérite d'une classe parent. Ses classes parent et enfant ont des variables d'instance avec le même nom. (Pas une variable de classe) La classe parente a une méthode qui vous permet de générer des variables d'instance vers la console.

Au moment de l'exécution, l'instance de classe enfant appelle la méthode parent héritée. Maintenant, l'histoire est ** Quelle variable d'instance sera sortie, parent ou enfant? ** …….

Si vous l'écrivez dans un code JS (ES6 ou ultérieur) que de nombreuses personnes peuvent probablement lire, c'est un tel code.

class SuperClass {
  constructor() {
    //* Dans JS, les variables d'instance sont définies à l'exécution, donc écrivez-les dans le constructeur.
    this.instanceVariable = "SuperClass" //Différentes valeurs avec le même nom
  }

  superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClass extends SuperClass {
  constructor() {
    super()
    this.instanceVariable = "SubClass" //Différentes valeurs avec le même nom
  }
}

const sub = new SubClass() //Intensifier la classe enfant
sub.superClassMethod() //Appelez la méthode de classe parent héritée

Imaginez quelles valeurs sont affichées dans la langue que vous utilisez normalement. C'est un style d'écriture occasionnel (bon ou mauvais), donc vous savez peut-être dans quoi vous êtes bon. Mais si vous savez comment cela fonctionne dans d'autres langues, cela peut être utile un jour lorsque vous entrez dans une autre entreprise ou un projet différent, ou lorsque vous souhaitez vous lancer dans une autre langue.

Cette fois, je regarde non seulement les variables d'instance mais aussi ce qui se passe lorsque vous retournez "SuperClass" `avec une méthode (une méthode d'une instance qui n'est pas une méthode de classe). Dans ce cas, la classe parent et la classe enfant ont une méthode avec le même nom et la méthode de la classe parent l'appelle ....

Vous pouvez découvrir quel code vous avez écrit et recherché

<détails>

Afficher le code (langue hoge) </ b> </ summary>

class Hoge {}

Puisque l'élément de pliage détaillé est placé comme ceci, vous pouvez lire le code à l'intérieur en cliquant dessus pour l'ouvrir. C'est un joli code WET qui utilise en principe le copier-coller pour vous permettre de voir plus facilement ce que vous faites, mais ne lancez pas Masakari parce que c'est intentionnel.

Le point de cette fois

Comme vous le savez, différents langages de programmation ont différentes grammaires et différentes méthodes d'évaluation. Je pense que les points qui changeront les résultats cette fois sont les suivants.

  • Le modificateur d'accès existe-t-il? Aussi, quel genre de choses y a-t-il
  • Est-il possible de définir des variables d'instance avec le même nom dans la classe parent et la classe enfant en premier lieu?
  • Existe-t-il des remplacements de variable d'instance et de méthode? ――Comment chaque langue gère l'héritage lui-même

Annonce des résultats

Java

Java, le champion des systèmes d'entreprise. Java a des modificateurs d'accès tels que «privé» et «protégé». private ne peut être vu que depuis la classe courante. protected est accessible depuis la classe actuelle et les classes enfants.

Il n'y a pas de remplacement de variable d'instance en Java. Voyons donc ce qui se passe lorsque nous le remplaçons par une méthode.

conditions résultat
La variable d'instance est privée "SuperClass"
Les variables d'instance sont protégées "SuperClass"
Méthode privée au lieu de la variable d'instance "SuperClass"
Méthode protégée (remplacement) au lieu de la variable d'instance "SubClass"

Remplace littéralement «écraser».

Cette fois, cela n'avait pas d'importance, mais Java vous permet d'accéder aux variables d'instance de la classe parent avec des méthodes du côté de la classe enfant comme super.instanceVariable. C'est une astuce que vous pouvez faire parce que vous ne la remplacez pas.

<détails>

Afficher le code (Java) </ b> </ summary>

public class JavaSample {
    public static void main(String[] args) {
        System.out.println("---- SubClass ----");
        SubClass sub = new SubClass();
        sub.superClassMethod();

        System.out.println("---- SubClassProtected ----");
        SubClassProtected subp = new SubClassProtected();
        subp.superClassMethod();

        System.out.println("---- SubClassGetter ----");
        SubClassGetter subg = new SubClassGetter();
        subg.superClassMethod();

        System.out.println("---- SubClassGetterProtected ----");
        SubClassGetterProtected subgp = new SubClassGetterProtected();
        subgp.superClassMethod();
    }
}

class SuperClass {
    //Les variables d'instance privée ne peuvent pas être référencées par des sous-classes
    private String instanceVariable = "SuperClass";

    public void superClassMethod() {
        System.out.println(instanceVariable);
    }
}

class SubClass extends SuperClass {
    private String instanceVariable = "SubClass";
}

// -------------------------------------------

class SuperClassProtected {
    protected String instanceVariable = "SuperClass";

    public void superClassMethod() {
        System.out.println(instanceVariable);
    }
}

class SubClassProtected extends SuperClassProtected {
    protected String instanceVariable = "SubClass";

    // public void subClassMethod() {
        // System.out.println(instanceVariable);Si vous écrivez
        // System.out.println(this.instanceVariable);Pareil que."SubClass"sortir.
        //Avec super,"SuperClass"Peut également être affiché
        // System.out.println(super.instanceVariable);
    // }
}

// -------------------------------------------

class SuperClassGetter {
    private String instanceVariable() {
        return "SuperClass";
    }

    public void superClassMethod() {
        System.out.println(instanceVariable());
    }
}

class SubClassGetter extends SuperClassGetter {
    private String instanceVariable() {
        return "SubClass";
    }
}

// -------------------------------------------

class SuperClassGetterProtected {
    protected String instanceVariable() {
        return "SuperClass";
    }

    public void superClassMethod() {
        System.out.println(instanceVariable());
    }
}

class SubClassGetterProtected extends SuperClassGetterProtected {
    protected String instanceVariable() {
        return "SubClass";
    }
}

C#

Après Java, C #. Il a une grammaire assez proche de Java pour des raisons historiques. Le résultat est également similaire à Java et C ++ décrit ci-dessous, mais il y en a que Java n'a pas. Au fait, C # a des propriétés, donc je les ai écrites comme des propriétés au lieu de méthodes.

C # a virtual et ʻoverride. virtual est un modificateur qui vous indique que cette méthode peut être surchargée, et ʻoverride est un modificateur qui vous indique que la méthode est remplacée ici.

C'est bien, mais C # a aussi un modificateur étrange appelé new. Ce nouveau est différent du nouveau du «nouvel Humain ()» au moment de l'instanciation. En ajoutant new au lieu de override, la méthode de la classe parent peut être évaluée dans le contexte de la classe parent même si elle est appelée depuis une classe enfant. La raison est que nous ne remplaçons pas les méthodes de la classe parente, nous les cachons simplement. C'est compliqué.

conditions résultat
La variable d'instance est privée "SuperClass"
Les variables d'instance sont protégées "SuperClass"
La propriété est privée "SuperClass"
Propriété protégée(override) "SubClass"
Propriété protégée(new) "SuperClass"

<détails>

Afficher le code (C #) </ b> </ summary>

using System;

public class CSharpSample
{
    public static void Main(string[] args)
    {
        Console.WriteLine("---- SubClass ----");
        var sub = new SubClass();
        sub.SuperClassMethod();

        Console.WriteLine("---- SubClassProtected ----");
        var subp = new SubClassProtected();
        subp.SuperClassMethod();

        Console.WriteLine("---- SubClassGetter ----");
        var subg = new SubClassGetter();
        subg.SuperClassMethod();

        Console.WriteLine("---- SubClassGetterProtectedOverride ----");
        var subgpo = new SubClassGetterProtectedOverride();
        subgpo.SuperClassMethod();

        Console.WriteLine("---- SubClassGetterProtectedNew ----");
        var subgpn = new SubClassGetterProtectedNew();
        subgpn.SuperClassMethod();
    }
}

class SuperClass
{
    private string instanceVariable = "SuperClass";

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClass : SuperClass
{
    // warning CS0414: The field 'SubClass.instanceVariable' is assigned but its value is never used
    private string instanceVariable = "SubClass";
}

// ----------------------------

class SuperClassProtected
{
    protected string instanceVariable = "SuperClass";

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClassProtected : SuperClassProtected
{
    //new n'est pas un remplacement, il indique explicitement qu'il masque la variable d'instance héritée
    new protected string instanceVariable = "SubClass";
}

// ----------------------------

class SuperClassGetter
{
    private string instanceVariable
    { 
        get { 
            return "SuperClass";
        }
    }

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClassGetter : SuperClassGetter
{
    private string instanceVariable {
        get {
            return "SubClass";
        }
    }
}

// ----------------------------

class SuperClassGetterProtected
{
    protected virtual string instanceVariable
    { 
        get { 
            return "SuperClass";
        }
    }

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClassGetterProtectedOverride : SuperClassGetterProtected
{
    protected override string instanceVariable {
        get {
            return "SubClass";
        }
    }
}

class SubClassGetterProtectedNew : SuperClassGetterProtected
{
    protected new string instanceVariable {
        get {
            return "SubClass";
        }
    }
}

C++

Il semble que C ++ soit souvent utilisé dans le domaine de l'incorporation, mais je ne sais rien. C ++ Nanimowa Karanai …….

Avec Java, c'est le langage original de C # et son comportement est très similaire à C #. Si vous utilisez une méthode au lieu d'une variable d'instance et que vous ne la remplacez pas, elle se comporte de la même manière que new en C #.

conditions résultat
La variable d'instance est privée "SuperClass"
Les variables d'instance sont protégées "SuperClass"
Méthode privée au lieu de la variable d'instance "SuperClass"
Méthode protégée (remplacement) au lieu de la variable d'instance "SubClass"
Méthode protégée au lieu de la variable d'instance (ne pas remplacer) "SuperClass"

<détails>

Afficher le code (C ++) </ b> </ summary>

#include <iostream>

class SuperClass {
//Privé par défaut (inaccessible de l'extérieur de la classe)
    std::string instanceVariable = "SuperClass";
public:
    void superClassMethod() {
        std::cout << instanceVariable << std::endl;
    }
};

class SubClass : public SuperClass {
    std::string instanceVariable = "SubClass";
};

// -------------------------------

class SuperClassProtected {
protected:
    std::string instanceVariable = "SuperClass";
public:
    void superClassMethod() {
        std::cout << instanceVariable << std::endl;
    }
};

class SubClassProtected : public SuperClassProtected {
protected:
    std::string instanceVariable = "SubClass";
};

// -------------------------------

class SuperClassGetter {
    std::string instanceVariable() {
        return "SuperClass";
    }
public:
    void superClassMethod() {
        std::cout << instanceVariable() << std::endl;
    }
};

class SubClassGetter : public SuperClassGetter {
    std::string instanceVariable() {
        return "SubClass";
    }
};

// -------------------------------

class SuperClassProtectedGetter {
protected:
    std::string instanceVariable() {
        return "SuperClass";
    }
public:
    void superClassMethod() {
        std::cout << instanceVariable() << std::endl;
    }
};

class SubClassProtectedGetter : public SuperClassProtectedGetter {
protected:
    std::string instanceVariable() {
        return "SubClass";
    }
};

// -------------------------------

class SuperClassProtectedGetterOverride {
protected:
    virtual std::string instanceVariable() {
        return "SuperClass";
    }
public:
    void superClassMethod() {
        std::cout << instanceVariable() << std::endl;
    }
};

class SubClassProtectedGetterOverride : public SuperClassProtectedGetterOverride {
protected:
    std::string instanceVariable() override {
        return "SubClass";
    }
};

int main()
{
    std::cout << "---- SubClass ----" << std::endl;
    SubClass sub;
    sub.superClassMethod();

    std::cout << "---- SubClassProtected ----" << std::endl;
    SubClassProtected subp;
    subp.superClassMethod();

    std::cout << "---- SubClassGetter ----" << std::endl;
    SubClassGetter subg;
    subg.superClassMethod();

    std::cout << "---- SubClassProtectedGetter ----" << std::endl;
    SubClassProtectedGetter subpg;
    subpg.superClassMethod();

    std::cout << "---- SubClassProtectedGetterOverride ----" << std::endl;
    SubClassProtectedGetterOverride subpgo;
    subpgo.superClassMethod();

    return 0;
}

Scala

AltJava qui intègre un style fonctionnel. La grande différence entre Java et C # est que vous pouvez ** remplacer les variables d'instance **. Les nouvelles fonctionnalités sont là!

conditions résultat
La variable d'instance est privée "SuperClass"
Variable d'instance protégée (remplacement) "SubClass"

<détails>

Afficher le code (Scala) </ b> </ summary>

object ScalaSample {
    def main(args: Array[String]): Unit = {
        println("---- SubClass ----")
        val sub = new SubClass
        sub.superClassMethod()
    
        println("---- SubClassProtected ----")
        val subp = new SubClassProtected
        subp.superClassMethod()
    }
}

class SuperClass {
    private val instanceVariable = "SuperClass";

    def superClassMethod(): Unit = {
        println(instanceVariable);
    }
}

class SubClass extends SuperClass {
    private val instanceVariable = "SubClass";
}

// ----------------------------

class SuperClassProtected {
    protected val instanceVariable = "SuperClass";

    def superClassMethod(): Unit = {
        println(instanceVariable);
    }
}

class SubClassProtected extends SuperClassProtected {
    override protected val instanceVariable = "SubClass";
}

Kotlin

Alt Java a été fortement influencé par Scala. Il est souvent utilisé dans le développement d'applications Android. Identique à Scala, sauf que la variable d'instance que vous prévoyez de remplacer doit être ouverte. Donc ʻopen est comme virtual` en C ++ ou C #.

conditions résultat
La variable d'instance est privée "SuperClass"
Variable d'instance protégée (remplacement) "SubClass"

<détails>

Afficher le code (Kotlin) </ b> </ summary>

fun main(args: Array<String>) {
    println("---- SubClass ----");
    val sub = SubClass();
    sub.superClassMethod();

    println("---- SubClassOverride ----");
    val subo = SubClassOverride();
    subo.superClassMethod();
}

open class SuperClass {
    private val instanceVariable = "SuperClass";

    fun superClassMethod() {
        println(instanceVariable);
    }
}

class SubClass : SuperClass() {
    private val instanceVariable = "SubClass";
}

// -----------------------------------

open class SuperClassOverride {
    open val instanceVariable = "SuperClass";

    fun superClassMethod() {
        println(instanceVariable);
    }
}

class SubClassOverride : SuperClassOverride() {
    override val instanceVariable = "SubClass";
}

Swift

Android n'est pas la seule application. Je ne veux pas que vous oubliez iOS. Il semble que le comportement de "private" de Swift change en fonction de la version, mais cette fois je l'ai vérifié avec Swift 5, donc comme Java, il n'est valide que dans la classe et n'est pas hérité.

«Let» de Swift est une déclaration de variable qui interdit la réaffectation. Dans JS, c'est const. Et «var» de Swift est une déclaration de variable réassignable normale. C'est «let» dans JS. C'est compliqué.

Dans Swift, vous ne pouvez pas définir une variable d'instance (appelée propriété dans Swift) qui est la même que la source d'héritage. Vous pouvez le remplacer en utilisant la propriété calculée (comme une propriété en C #) à la place.

Sans un modificateur d'accès tel que private, la portée sera ʻinternal. ʻInternal est comme public en Java (divers).

conditions résultat
La variable d'instance est privée "SuperClass"
La variable d'instance est interne Indéfinissable
La propriété calculée est privée "SuperClass"
La propriété calculée est interne(override) "SubClass"

<détails>

Afficher le code (Swift) </ b> </ summary>

class SuperClass {
  private let instanceVariable = "SuperClass";

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClass: SuperClass {
  private let instanceVariable = "SubClass";
}

// --------------------------------

class SuperClassInternal {
  let instanceVariable = "Error";

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClassInternal: SuperClassInternal {
  // error: cannot override with a stored property 'instanceVariable'
  // let instanceVariable = "SubClass";
}

// --------------------------------

//Faites-en une propriété calculée et développez un getter. Dans ce cas, il est traité comme une fonction, vous pouvez donc le remplacer.
class SuperClassGetter {
  //Si c'est laissé, erreur: 'let' declarations cannot be computed properties
  private var instanceVariable: String { get { return "SuperClass" } }

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClassGetter: SuperClassGetter {
  private var instanceVariable: String { get { return "SubClass" } };
}

// --------------------------------

//Faites-en une propriété calculée et développez un getter. Dans ce cas, il est traité comme une fonction, vous pouvez donc le remplacer.
class SuperClassInternalGetter {
  //Si c'est laissé, erreur: 'let' declarations cannot be computed properties
  var instanceVariable: String { get { return "SuperClass" } }

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClassInternalGetter: SuperClassInternalGetter {
  override var instanceVariable: String { get { return "SubClass" } };
}

print("---- SubClass ----");
let sub = SubClass();
sub.SuperClassMethod();

print("---- SubClassInternal ----");
let subi = SubClassInternal();
subi.SuperClassMethod();

print("---- SubClassGetter ----");
let subg = SubClassGetter();
subg.SuperClassMethod();

print("---- SubClassInternalGetter ----");
let subig = SubClassInternalGetter();
subig.SuperClassMethod();

Python

A partir de là, un langage typé dynamiquement! Python a rendu sa popularité solide, en continuant à occuper la première place dans le classement des publications d'étiquettes de Qiita.

La caractéristique des classes Python est que l'instance elle-même arrive au premier argument de la méthode, donc lorsque vous la déclarez, écrivez self comme premier argument. Il n'est pas nécessaire que ce soit «soi», mais tout le monde s'écrit «soi».

Après cela, comme un langage typé dynamiquement, les variables d'instance sont créées dynamiquement, définissez donc les variables d'instance dans le constructeur plutôt que directement sous la déclaration de classe. C'est la même chose pour Ruby et JavaScript.

Python n'a aucune restriction d'accès aux membres. Il n'y a pas de modificateur «privé». C'est une culture qui préfixe le nom de la fonction avec ** 1 ** pour indiquer que vous ne souhaitez pas y accéder.

Mais en Python, il existe une fonctionnalité au cas où il y aurait un conflit de nom avec une classe enfant. L'ajout de ** 2 ** souligne modifie le nom du membre interne (modification du nom) et facilite l'accès au nom de la variable d'origine. Cette fonctionnalité vous permet d'évaluer les résultats lors de l'exécution dans le contexte de la classe parent d'origine, même si la classe enfant a des membres portant le même nom. pep8-ja - convention de dénomination - nom de méthode et variable d'instance Voyons le résultat.

conditions résultat
Variable d'instance "SubClass"
Méthode au lieu de la variable d'instance "SubClass"
Variable d'instance (avec 2 Ansco) "SuperClass"
Méthode au lieu de variable d'instance (avec 2 Ansco) "SuperClass"

<détails>

Afficher le code (Python) </ b> </ summary>

class SuperClass:
  def __init__(self):
    self.instance_variable = "SuperClass"

  def super_class_method(self):
    print(self.instance_variable)

class SubClass(SuperClass):
  def __init__(self):
    super().__init__()
    self.instance_variable = "SubClass"

# ------------------------------

class SuperClassNameMangling:
  def __init__(self):
    self.__instance_variable = "SuperClass"

  def super_class_method(self):
    print(self.__instance_variable)

class SubClassNameMangling(SuperClassNameMangling):
  def __init__(self):
    super().__init__()
    self.__instance_variable = "SubClass"

# ------------------------------

class SuperClassGetter:
  def instance_variable(self):
    return "SuperClass"

  def super_class_method(self):
    print(self.instance_variable())

class SubClassGetter(SuperClassGetter):
  def instance_variable(self):
    return "SubClass"

# ------------------------------

class SuperClassNameManglingGetter:
  def __instance_variable(self):
    return "SuperClass"

  def super_class_method(self):
    print(self.__instance_variable())

class SubClassNameManglingGetter(SuperClassNameManglingGetter):
  def __instance_variable(self):
    return "SubClass"

print('---- SubClass ----')
sub = SubClass()
sub.super_class_method()

print('---- SubClassNameMangling ----')
subp = SubClassNameMangling()
subp.super_class_method()

print('---- SubClassGetter ----')
subg = SubClassGetter()
subg.super_class_method()

print('---- SubClassNameManglingGetter ----')
subpg = SubClassNameManglingGetter()
subpg.super_class_method()

Ruby

"Qu'en est-il d'un langage à typage dynamique orienté objet?" De nombreux programmeurs qui ont répondu au quiz associatif pensent en premier à ce langage.

Ruby a un privé que vous pouvez utiliser pour les méthodes, mais il se comporte différemment d'un langage comme Java. Je ne l'écrirai pas en détail car je dois expliquer le récepteur etc., mais pour le moment, je peux dire que même s'il y a «private», la méthode peut être vue dans la destination d'héritage. Donc, en Java, «protected» peut être plus proche. [Ruby] L'essence des méthodes privées et les avantages de les comprendre

À propos, dans Ruby, les espaces de noms des variables et des méthodes sont séparés, vous pouvez donc les appeler même si vous écrivez la méthode sans parenthèses. La méthode retourne ensuite le résultat de la dernière expression évaluée sans écrire de retour. @ Variagename est la variable d'instance. Dans Ruby, vous pouvez indiquer le type (portée) d'une variable par le premier caractère du nom de la variable.

conditions résultat
Variable d'instance "SubClass"
Méthode au lieu de la variable d'instance "SubClass"
Méthode privée au lieu de la variable d'instance "SubClass"

<détails>

Afficher le code (Ruby) </ b> </ summary>

class SuperClass
  def initialize()
    @instance_variable = "SuperClass"
  end

  def super_class_method
    p @instance_variable
  end
end

class SubClass < SuperClass
  def initialize()
    super()
    @instance_variable = "SubClass"
  end
end

# --------------------------------

class SuperClassGetter
  def instance_variable()
    "SuperClass"
  end

  def super_class_method
    p instance_variable
  end
end

class SubClassGetter < SuperClassGetter
  def instance_variable()
    "SubClass"
  end
end

# --------------------------------

class SuperClassGetterPrivate
  def super_class_method
    p instance_variable
  end

  private

  def instance_variable()
    "SuperClass"
  end
end

class SubClassGetterPrivate < SuperClassGetterPrivate
  private
  
  def instance_variable()
    "SubClass"
  end
end

p '---- SubClass ----'
subc = SubClass.new
subc.super_class_method

p '---- SubClassGetter ----'
subg = SubClassGetter.new
subg.super_class_method

p '---- SubClassGetterPrivate ----'
subgp = SubClassGetterPrivate.new
subgp.super_class_method

PHP

PHP a private, protected et public comme Java. Ce n'est fondamentalement pas en Python, Ruby ou JavaScript! Jaloux! Mais contrairement à Java, les variables d'instance protected vont lire les sous-classes. C'est un mouvement qui est en ligne avec d'autres langages typés dynamiquement.

conditions résultat
La variable d'instance est privée "SuperClass"
Les variables d'instance sont protégées "SubClass"
Méthode privée au lieu de la variable d'instance "SuperClass"
Méthode protégée au lieu de la variable d'instance "SubClass"

<détails>

Afficher le code (PHP) </ b> </ summary>

<?php
function println($message)
{
    echo $message.PHP_EOL;
}

// ----------------------------------------

class SuperClass
{
    private $instanceVariable = "SuperClass";

    public function superClassMethod()
    {
        println($this->instanceVariable);
    }
}

class SubClass extends SuperClass
{
    private $instanceVariable = "SubClass";
}

// ----------------------------------------

class SuperClassProtected
{
    protected $instanceVariable = "SuperClass";

    public function superClassMethod()
    {
        println($this->instanceVariable);
    }
}

class SubClassProtected extends SuperClassProtected
{
    protected $instanceVariable = "SubClass";
}

// ----------------------------------------

class SuperClassGetter
{
    private function instanceVariable()
    {
        return "SuperClass";
    }
    
    public function superClassMethod()
    {
        println($this->instanceVariable());
    }
}

class SubClassGetter extends SuperClassGetter
{
    private function instanceVariable()
    {
        return "SubClass";
    }
}

// ----------------------------------------

class SuperClassGetterProtected
{
    protected function instanceVariable()
    {
        return "SuperClass";
    }
    
    public function superClassMethod()
    {
        println($this->instanceVariable());
    }
}

class SubClassGetterProtected extends SuperClassGetterProtected
{
    protected function instanceVariable()
    {
        return "SubClass";
    }
}

// ----------------------------------------

println("---- SubClass ----");
$sub = new SubClass();
$sub->superClassMethod();

println("---- SubClassProtected ----");
$subp = new SubClassProtected();
$subp->superClassMethod();

println("---- SubClassGetter ----");
$subg = new SubClassGetter();
$subg->superClassMethod();

println("---- SubClassGetterProtected ----");
$subgp = new SubClassGetterProtected();
$subgp->superClassMethod();

JavaScript

Le champion du front-end. Un langage orienté objet basé sur un prototype, un langage inspiré du langage de programmation Self. Étant donné que ES6 et les versions ultérieures JavaScript incorporent également l'écriture basée sur les classes, elles peuvent être héritées par ʻextends`.

conditions résultat
Variable d'instance "SubClass"
Variables d'instance dans l'ancien format "SubClass"
Dans la variable d'instance, la méthode d'appel est une fonction de flèche "SubClass"
Fonction de flèche au lieu de variable d'instance "SubClass"

<détails>

Afficher le code (JavaScript) </ b> </ summary>

class SuperClass {
  constructor() {
    this.instanceVariable = "SuperClass"
  }

  superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClass extends SuperClass {
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

// ------------------------

function LegacySuperClass() {
  this.instanceVariable = "SuperClass";
};
LegacySuperClass.prototype.superClassMethod = function() {
  console.log(this.instanceVariable)
}; 

function LegacySubClass() {
  this.instanceVariable = "SubClass";
};
LegacySubClass.prototype = new LegacySuperClass();

// ------------------------

class SuperClassArrow {
  constructor() {
    this.instanceVariable = "SuperClass"
  }

  superClassMethod = () => {
    console.log(this.instanceVariable)
  }
}

class SubClassArrow extends SuperClassArrow {
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

// ------------------------

class SuperClassGetterArrow {
  instanceVariable = () => {
    return "SuperClass"
  }

  superClassMethod = () => {
    console.log(this.instanceVariable())
  }
}

class SubClassGetterArrow extends SuperClassGetterArrow {
  instanceVariable = () => {
    return "SubClass"
  }
}

// ------------------------

console.log('---- SubClass ----')
const sub = new SubClass()
sub.superClassMethod()

console.log('---- LegacySubClass ----')
var lsub = new LegacySubClass()
lsub.superClassMethod()

console.log('---- SubClassArrow ----')
const suba = new SubClassArrow()
suba.superClassMethod()

console.log('---- SubClassGetterArrow ----')
const subga = new SubClassGetterArrow()
subga.superClassMethod()

TypeScript

C'est un JavaScript cool qui peut être typé statiquement. Il existe des types d'union, qui sont similaires aux types trouvés dans Haskell, qui a un système de type avancé, et il existe des types conditionnels, des types mappés et d'autres types expressifs.

Dans TypeScript, la définition d'un membre avec le même nom que private dans une classe parent et une classe enfant entraînera une erreur de compilation. S'il est "protégé", il n'y a pas de problème. C'est exactement le contraire de Swift.

conditions résultat
La variable d'instance est privée Indéfinissable
Les variables d'instance sont protégées "SubClass"
Méthode privée au lieu de la variable d'instance Indéfinissable
La variable d'instance est protégée et la méthode d'appel est une fonction fléchée "SubClass"
Fonction de flèche protégée au lieu de variable d'instance "SubClass"

<détails>

Afficher le code (TypeScript) </ b> </ summary>

class SuperClass {
  private readonly instanceVariable: string

  constructor() {
    this.instanceVariable = "Error"
  }

  public superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClass extends SuperClass {
  //Lorsque vous essayez de définir avec instanceVariable
  // TS2415: Class 'SubClass' incorrectly extends base class 'SuperClass'.
  // private readonly instanceVariable: string

  // constructor() {
  //   super()
  //   this.instanceVariable = "SubClass"
  // }
}

// ------------------------

class SuperClassGetter {
  private instanceVariable() {
    return "Error"
  }

  public superClassMethod() {
    console.log(this.instanceVariable())
  }
}

class SubClassGetter extends SuperClassGetter {
  //Lorsque vous essayez de définir avec instanceVariable
  // TS2415: Class 'SubClassGetter' incorrectly extends base class 'SuperClassGetter'.
  // Types have separate declarations of a private property 'instanceVariable'.
  // private instanceVariable() {
  //   return "SubClass"
  // }
}

// ------------------------

class SuperClassProtected {
  protected readonly instanceVariable: string

  constructor() {
    this.instanceVariable = "SuperClass"
  }

  public superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClassProtected extends SuperClassProtected {
  protected readonly instanceVariable: string
  
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

// ------------------------

class SuperClassProtectedGetterArrow {
  protected instanceVariable = () => {
    return "SuperClass"
  }

  public superClassMethod = () => {
    console.log(this.instanceVariable())
  }
}

class SubClassProtectedGetterArrow extends SuperClassProtectedGetterArrow {
  protected instanceVariable = () => {
    return "SubClass"
  }
}

// ------------------------

//Version de la fonction flèche
class SuperClassProtectedArrow {
  protected readonly instanceVariable: string

  constructor() {
    this.instanceVariable = "SuperClass"
  }

  public superClassMethod = () => {
    console.log(this.instanceVariable)
  }
}

class SubClassProtectedArrow extends SuperClassProtectedArrow {
  protected readonly instanceVariable: string
  
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

console.log('---- SubClass ----')
const sub = new SubClass()
sub.superClassMethod()

console.log('---- SubClassGetter ----')
const subg = new SubClassGetter()
subg.superClassMethod()

console.log('---- SubClassProtected ----')
const subp = new SubClassProtected()
subp.superClassMethod()

console.log('---- SubClassProtectedArrow ----')
const subpa = new SubClassProtectedArrow()
subpa.superClassMethod()

console.log('---- SubClassProtectedGetterArrow ----')
const subpga = new SubClassProtectedGetterArrow()
subpga.superClassMethod()

Dart

C'est une langue impressionnante qui a soudainement une présence depuis que Flutter est devenu populaire. Dart n'écrit pas «privé» ou «public». Vous pouvez le rendre privé en ajoutant un trait de soulignement au nom du membre, mais il est différent de private tel que Java car il ne le rend invisible que de l'extérieur de la bibliothèque.

conditions résultat
Variable d'instance (avec ansco) "SubClass"
Variable d'instance "SubClass"
Méthode au lieu de la variable d'instance "SubClass"

<détails>

Afficher le code (Dart) </ b> </ summary>

void main() {
  print("---- SubClassPrivate ----");
  final subp = new SubClassPrivate();
  subp.superClassMethod();

  print("---- SubClass ----");
  final sub = new SubClass();
  sub.superClassMethod();

  print("---- SubClassGetter ----");
  final subg = new SubClassGetter();
  subg.superClassMethod();
}

class SuperClassPrivate {
  //Si vous donnez un trait de soulignement, ce sera Privé,
  //Puisque private est visible dans la même bibliothèque, cela semble normal à partir de la sous-classe ici
  final String _instanceVariable = "SuperClass";

  void superClassMethod() => print(_instanceVariable);
}

class SubClassPrivate extends SuperClassPrivate {
  final String _instanceVariable = "SubClass";
}

// ------------------------------------

class SuperClass {
  final String instanceVariable = "SuperClass";

  void superClassMethod() => print(instanceVariable);
}

class SubClass extends SuperClass {
  final String instanceVariable = "SubClass";
}

// ------------------------------------

class SuperClassGetter {
  String instanceVariable() => "SuperClass";

  void superClassMethod() => print(instanceVariable());
}

class SubClassGetter extends SuperClassGetter {
  String instanceVariable() => "SubClass";
}

Résumé

C'était étonnamment amusant parce qu'il y avait des choses que je ne savais même pas dans une langue dans laquelle j'étais habitué dans une certaine mesure. Certains des exemples que j'ai écrits pour la première fois cette fois, voici comment les écrire! Ou quelque chose ne va pas! Veuillez commenter si vous en avez.

Dans l'ensemble, j'avais l'impression que dans un langage typé dynamiquement, même lorsqu'une méthode de superclasse était appelée, elle serait d'abord évaluée dans le contexte d'une sous-classe. D'un autre côté, dans le langage typé statiquement, c'était comme: "Parce que c'est une méthode d'une superclasse, les bases sont évaluées par la superclasse, mais si vous la remplacez, ce n'est pas le cas."

Les cinq suivants étaient personnellement impressionnants.

--C # a un modificateur non prioritaire appelé nouveau --Scala et Kotlin sont des langages typés statiquement mais peuvent remplacer les variables d'instance --Python souligné Les deux noms de membres étaient plus que de simples noms, ils avaient aussi un effet --PHP a un privé comme Java même s'il s'agit d'un langage typé dynamiquement --TypeScript empêche les membres privés en double avec le même nom de provoquer une erreur au moment de la compilation et de provoquer un comportement inattendu.

Journal des modifications

  • Correction d'une erreur dans l'explication de la convention de dénomination Python. Merci @shiracamus. --Il a été souligné que le mot «privé» n'est pas utilisé en Python, donc je l'ai corrigé. Merci @Luice.

Recommended Posts