언어마다 다른 것 · 37
클래스와 객체
데이터(필드)와 동작(메서드)을 한 틀에 묶고, 그 틀로 객체를 여러 개 만들어요.
이 단원은 Python · JavaScript · TypeScript · Java · C# · C++에서 배워요.
C에는 클래스가 없어서 구조체(struct)와 함수로 같은 일을 해요(구조체 단원 참고).
크레이콘은 직접 만드는 클래스가 없고 사전()에 학생["이름"]처럼 담아요.
클래스는 설계도이고, 객체는 그 설계도로 찍어 낸 실물이에요.
아래 예제는 이름과 점수를 가진 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(); } |
자주 하는 실수
객체 내용을 ==로 비교했어요Java · C#
new Student("Mina", 82) == new Student("Mina", 82)→ false — ==는 같은 객체인지를 봐요. equals도 다시 정의하기 전에는 ==와 똑같이 동작해요
내용은 equals(C#은 Equals)로 비교하고, 그 메서드를 직접 다시 정의하거나 record를 써요.
메서드에 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으로 받고, 생성자 안에서 새 목록을 만들어요.
언어마다 다른 점
C++는 객체가 값이라
b = a 다음에 b를 바꾸면 Python·JavaScript·TypeScript·Java·C#에서는 a도 바뀌어요(두 이름이 같은 객체를 가리켜요).C++는 객체가 값이라
Student b = a;와 for (Student s : students)가 복사본을 만들어서, 원본을 다루려면 Student&(읽기만 하면 const Student&)를 써요.