言語ごとの特徴 · 37
クラスとオブジェクト
データ(フィールド)と動作(メソッド)をひとつの型にまとめ、その型からオブジェクトをいくつも作ります。
この単元は Python · JavaScript · TypeScript · Java · C# · C++ 向けです。
C にはクラスがなく、構造体(struct)と関数で同じことをします(構造体の単元を参照)。
Craykon には自分で作るクラスがなく、辞書() に 学生["名前"] のように入れます。
クラスは設計図で、オブジェクトはその設計図から作った実物です。
下の例は名前と点数を持つ Student クラスで学生を何人か作り、点数の高い順に並べて成績といっしょに表示します。
class Student: def __init__(self, name, score): self.name = name self.score = score def grade(self): if self.score >= 90: return "A" if self.score >= 80: return "B" return "C" def describe(self): return f"{self.name} {self.score} {self.grade()}" n = int(input())students = []for _ in range(n): name, score = input().split() students.append(Student(name, int(score))) students.sort(key=lambda s: s.score, reverse=True)for s in students: print(s.describe())class Student { constructor(name, score) { this.name = name; this.score = score; } grade() { if (this.score >= 90) return "A"; if (this.score >= 80) return "B"; return "C"; } describe() { return `${this.name} ${this.score} ${this.grade()}`; }} const lines = require("fs").readFileSync(0, "utf8").trim().split("\n");const n = Number(lines[0]);const students = [];for (let i = 1; i <= n; i++) { const [name, score] = lines[i].trim().split(" "); students.push(new Student(name, Number(score)));} students.sort((a, b) => b.score - a.score);for (const s of students) console.log(s.describe());import { readFileSync } from "node:fs"; class Student { readonly name: string; score: number; constructor(name: string, score: number) { this.name = name; this.score = score; } grade(): string { if (this.score >= 90) return "A"; if (this.score >= 80) return "B"; return "C"; } describe(): string { return `${this.name} ${this.score} ${this.grade()}`; }} const lines: string[] = readFileSync(0, "utf8").trim().split("\n");const n: number = Number(lines[0]);const students: Student[] = [];for (let i = 1; i <= n; i++) { const [name, score] = lines[i].trim().split(" "); students.push(new Student(name, Number(score)));} students.sort((a, b) => b.score - a.score);for (const s of students) console.log(s.describe());import java.util.*; class Student { private final String name; private final int score; Student(String name, int score) { this.name = name; this.score = score; } int getScore() { return score; } String grade() { if (score >= 90) return "A"; if (score >= 80) return "B"; return "C"; } String describe() { return name + " " + score + " " + grade(); }} public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); List<Student> students = new ArrayList<>(); for (int i = 0; i < n; i++) { students.add(new Student(sc.next(), sc.nextInt())); } students.sort(Comparator.comparingInt(Student::getScore).reversed()); for (Student s : students) System.out.println(s.describe()); }}using System;using System.Collections.Generic; class Student{ public string Name { get; } public int Score { get; } public Student(string name, int score) { Name = name; Score = score; } public string Grade() { if (Score >= 90) return "A"; if (Score >= 80) return "B"; return "C"; } public string Describe() => $"{Name} {Score} {Grade()}";} class Program{ static void Main() { int n = int.Parse(Console.ReadLine()); var students = new List<Student>(); for (int i = 0; i < n; i++) { string[] parts = Console.ReadLine().Split(' '); students.Add(new Student(parts[0], int.Parse(parts[1]))); } students.Sort((a, b) => b.Score.CompareTo(a.Score)); foreach (var s in students) Console.WriteLine(s.Describe()); }}#include <algorithm>#include <iostream>#include <string>#include <utility>#include <vector> class Student {public: Student(std::string name, int score) : name_(std::move(name)), score_(score) {} int score() const { return score_; } std::string grade() const { if (score_ >= 90) return "A"; if (score_ >= 80) return "B"; return "C"; } std::string describe() const { return name_ + " " + std::to_string(score_) + " " + grade(); } private: std::string name_; int score_;}; int main() { int n; std::cin >> n; std::vector<Student> students; for (int i = 0; i < n; i++) { std::string name; int score; std::cin >> name >> score; students.emplace_back(name, score); } std::sort(students.begin(), students.end(), [](const Student& a, const Student& b) { return a.score() > b.score(); }); for (const Student& s : students) std::cout << s.describe() << '\n';}3 Mina 82 Joon 95 Sora 78
Joon 95 A Mina 82 B Sora 78 C
ポイント
- クラスには、オブジェクトが持つデータ(フィールド)とオブジェクトができること(メソッド)を書きます。
- コンストラクタは、オブジェクトを作るときに最初の値を入れる特別な関数です。
- メソッドの中でオブジェクト自身は
this(Python はself)です。
引数と名前が重なるときはthis.name = nameのように区別します。 - アクセス修飾子(
public・private)で、外から使えるメンバーを決めます。
フィールドはふつう隠して、メソッドやプロパティで読ませます。 - オブジェクトのリストはフィールドを基準に並べ替えます。
並べ替えの関数に「何を比べるか」を渡します。
言語ごとの書き方
| Python | class Student: の中にコンストラクタ def __init__(self, name, score):。フィールドは self.name = name のように作り、すべてのメソッドの最初の引数は self。オブジェクトは new なしで Student("Mina", 82)。並べ替え: students.sort(key=lambda s: s.score, reverse=True) |
|---|---|
| JavaScript | class Student { constructor(name, score) { this.name = name; } }。オブジェクトは new Student("Mina", 82) で作り、new を忘れると TypeError: Class constructor Student cannot be invoked without 'new'。並べ替え: students.sort((a, b) => b.score - a.score) |
| TypeScript | JavaScript と同じ形で、フィールドを score: number; のように先に宣言します。private・readonly はコンパイル時だけの検査で、実行時には消えます。本当に隠すなら JavaScript の非公開フィールド #score |
| Java | コンストラクタはクラス名と同じで、戻り値の型を書きません。 フィールドは private で隠し、getScore() のようなゲッターで読みます。修飾子を書かないと同じパッケージの中だけで見えます。 並べ替え: students.sort(Comparator.comparingInt(Student::getScore).reversed()) |
| C# | プロパティ public int Score { get; } を使うと、外からは s.Score とフィールドのように読めます。修飾子を書かないメンバーは private。並べ替え: students.Sort((a, b) => b.Score.CompareTo(a.Score)) |
| C++ | class は既定が private、struct は public で、違いはそれだけなので public:・private: を自分で書きます。コンストラクタは初期化リスト : name_(name), score_(score)、メソッドの後ろの const は「オブジェクトを変えない」という約束。オブジェクトは new なしで値として Student s("Mina", 82);。並べ替え: std::sort にラムダ [](const Student& a, const Student& b) { return a.score() > b.score(); } |
よくある間違い
メソッドに self を書き忘れたPython
class Student:
def grade():
return "A"
Student().grade()→ TypeError: Student.grade() takes 0 positional arguments but 1 was given。メソッドの中で self. なしに score と書くと NameError です
最初の引数に self を置き、フィールドはいつも self.score のように読みます。
既定値にリスト [] を置いたPython
def __init__(self, name, tags=[]):
self.tags = tags→ そのリストは def が実行されたときに一度だけ作られます。ある学生に入れたタグがほかの学生にも見えます
tags=None で受け取り、コンストラクタの中で新しいリストを作ります。
オブジェクトの中身を == で比べたJava · C#
new Student("Mina", 82) == new Student("Mina", 82)→ false — == は同じオブジェクトかどうかを見ます。equals も定義し直すまでは == とまったく同じ動きです
中身は equals(C# は Equals)で比べ、そのメソッドを自分で定義し直すか record を使います。
言語ごとの違い
C++ はオブジェクトが値なので
b = a のあと b を変えると、Python・JavaScript・TypeScript・Java・C# では a も変わります(2つの名前が同じオブジェクトを指すからです)。C++ はオブジェクトが値なので
Student b = a; や for (Student s : students) はコピーを作り、元のものを扱うには Student&(読むだけなら const Student&)を使います。