함수 오버로딩(Function Overloading)을 지원하는 프로그래밍 언어와 각각의 예제
C++
#include <iostream>
using namespace std;
class Example {
public:
void display(int a) {
cout << "정수: " << a << endl;
}
void display(double b) {
cout << "실수: " << b << endl;
}
};
int main() {
Example obj;
obj.display(10); // 정수 호출
obj.display(3.14); // 실수 호출
return 0;
}
JAVA
class Example {
void display(int a) {
System.out.println("정수: " + a);
}
void display(double b) {
System.out.println("실수: " + b);
}
}
public class Main {
public static void main(String[] args) {
Example obj = new Example();
obj.display(10); // 정수 호출
obj.display(3.14); // 실수 호출
}
}
C#
using System;
class Example {
public void Display(int a) {
Console.WriteLine("정수: " + a);
}
public void Display(double b) {
Console.WriteLine("실수: " + b);
}
}
class Program {
static void Main() {
Example obj = new Example();
obj.Display(10); // 정수 호출
obj.Display(3.14); // 실수 호출
}
}
Swift
class Example {
func display(a: Int) {
print("정수: \(a)")
}
func display(b: Double) {
print("실수: \(b)")
}
}
let obj = Example()
obj.display(a: 10) // 정수 호출
obj.display(b: 3.14) // 실수 호출
Kotlin
class Example {
fun display(a: Int) {
println("정수: $a")
}
fun display(b: Double) {
println("실수: $b")
}
}
fun main() {
val obj = Example()
obj.display(10) // 정수 호출
obj.display(3.14) // 실수 호출
}
캡슐화(Encapsulation):
데이터(속성)와 메서드(동작)를 하나의 단위인 객체로 묶는 것입니다. 이를 통해 객체의 내부 상태를 보호하고, 외부에서 직접 접근하지 못하도록 제한합니다. 객체의 내부 구현은 숨겨지고, 공개된 인터페이스(메서드)를 통해 상호작용합니다.
상속(Inheritance):
기존 클래스(부모 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스)가 물려받는 기능입니다. 이를 통해 코드의 재사용성을 높이고, 공통된 기능을 부모 클래스에 정의하여 자식 클래스에서 쉽게 사용할 수 있습니다.
다형성(Polymorphism):
동일한 이름의 메서드가 서로 다른 클래스에서 다르게 동작하도록 하는 기능입니다. 주로 가상 함수와 오버로딩을 통해 구현됩니다. 이를 통해 코드의 유연성을 높이고, 다양한 객체를 동일한 방식으로 처리할 수 있습니다.
추상화(Abstraction):
복잡한 시스템을 단순화하여 중요한 부분만을 모델링하는 과정입니다. 객체의 중요한 속성과 동작만을 공개하고, 불필요한 세부사항은 숨깁니다. 인터페이스나 추상 클래스를 통해 구현할 수 있습니다.

코어션 : 자료형이 다른 계산을 할 때 자동으로 형변환이 되는 것
템플릿 (Generic function) : < >를 쓰고 C++, Java, C# 등에서 제네릭 타입을 정의할 때 사용


이렇게 int형,float형으로 나눠져있는 코드를 컴파일러가 솎아내 이름이 똑같더라도 자료형에 따라 자동적으로 불러옴.
#include <iostream>
int add(int i, int j)
{
return (i + j);
}
double add(double i, double j)
{
return (i + j);
}
double add(int i, int j)
{
return ((double)i + (double)j);
}
int main()
{
std::cout << add(10, 20) << std::endl;
std::cout << add(10.5, 20.3) << std::endl;
return 0;
}
위 코드와 같이 자료형은 같고 리턴형만 다른 경우 오버로드가 되지 않는다.
리턴이 되게 하려고 한다면 자료형이 다르거나 개수가 달라야한다.
#include <iostream>
int Max(int i, int j)
{
return i > j ? i : j;
}
double Max(double i, double j)
{
return i > j ? i : j;
}
char Max(char i, char j)
{
return i > j ? i : j;
}
int main()
{
std::cout << Max(1, 2) << std::endl;
std::cout << Max(7.5, 3.6) << std::endl;
std::cout << Max('A', 'B');
return 0;
}
이 소스를 다르게 변환시킬 수 있다.
#include <iostream>
template<class T>
T Max(T i, T j)
{
return i > j ? i : j;
}
int main()
{
std::cout << Max(1, 2) << std::endl;
std::cout << Max(7.5, 3.6) << std::endl;
std::cout << Max('A', 'B');
return 0;
}
template을 쓴 결과다.

이름이 같더라도 함수중첩을 할 수 있게 하려면 자료형이 다르거나, 매개변수의 개수가 달라야한다.
#include <iostream>
int add(int i, int j)
{
return (i + j);
}
float add(float i, float j)
{
return (i + j);
}
double add(double i, double j)
{
return (i + j);
}
int add(int i, int j, int k)
{
return (i + j + k);
}
int add(int i, int j, int k, int l)
{
return (i + j + k + l);
}
int main()
{
std::cout << add(1, 2) << std::endl;
std::cout << add(1.3f, 2.6f) << std::endl;
std::cout << add(6.5, 3.8) << std::endl;
std::cout << add(1, 2, 3) << std::endl;
std::cout << add(1, 2, 3, 4) << std::endl;
return 0;
}
이렇게 이름이 같더라도 자료형이 다르거나 개수가 다르다면 모두 자동형변환이 되어 출력이 가능하다.
1단계
#include <iostream>
class Dog {
};
int main()
{
return 0;
}
2단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
};
int main()
{
return 0;
}
3단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
getAge() { //getAge, setAge 만들기
}
setAge() {
}
};
int main()
{
return 0;
}
4단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
setAge() {
}
};
int main()
{
return 0;
}
5단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
return 0;
}
6단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
Dog coco;
std::cout << coco.getAge(); // coco.getAge 만들기
return 0;
}

입력 함수가 없기때문에 쓰레기 값 출력
7단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
Dog coco;
coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge(); // coco.getAge 만들기
return 0;
}
8단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
Dog() { //생성자는 class 이름과 똑같다.
}
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
Dog coco;
coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge(); // coco.getAge 만들기
return 0;
}
생성자는 class 이름과 똑같다
9단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
Dog() { //생성자는 class 이름과 똑같다.
age = 1;
}
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
Dog coco;
// coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge(); // coco.getAge 만들기
return 0;
}
이렇게 coco.setAge를 주석처리한다고 하더라도 쓰레기 값이 아닌 1이 출력되게 된다.
생성자 함수는 특이하게 return값이 없어도 void를 쓰지않는다.
10단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
Dog() { //생성자는 class 이름과 똑같다.
age = 1;
}
Dog(int a) {
age = a; //생성자를 2개만들고 기능을 살짝 변경해서 만들기
}
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
Dog coco,happy(5);
// coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge() << std::endl; // coco.getAge 만들기
std::cout << happy.getAge() << std::endl; // happy의 나이 출력하기
return 0;
}
11단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
Dog() { //생성자는 class 이름과 똑같다.
age = 1;
}
Dog(int a) {
age = a; //생성자를 2개만들고 기능을 살짝 변경해서 만들기
}
~Dog() { //소멸자 함수는 생성자와 구분하기위해 "~"를 앞에 붙여준다.
std::cout << "bye!\n";
}
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
int main()
{
Dog coco,happy(5);
// coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge() << std::endl; // coco.getAge 만들기
std::cout << happy.getAge() << std::endl; // happy의 나이 출력하기
return 0;
}
12단계
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
Dog() { //생성자는 class 이름과 똑같다.
age = 1;
}
Dog(int a) {
age = a; //생성자를 2개만들고 기능을 살짝 변경해서 만들기
}
~Dog() { //소멸자 함수는 생성자와 구분하기위해 "~"를 앞에 붙여준다.
std::cout << "bye!\n";
}
int getAge() { //getAge, setAge 만들기
return age; // int, return age; 만들기
}
void setAge(int a) { //void, int a선언 후 age = a; 만들기
age = a;
}
};
Dog::Dog() { age = 1; }
Dog::Dog(int a) { age = a; }
Dog::~Dog() { std::cout << "bye!\n"; }
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; }
int main()
{
Dog coco, happy(5);
// coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge() << std::endl; // coco.getAge 만들기
std::cout << happy.getAge() << std::endl; // happy의 나이 출력하기
return 0;
}

Default parameter에 대해 프로그래밍 언어별로 알려달라고 했을때의 결과값이다.
#include <iostream>
int add(int i = 1, int j = 2) // 형식매개변수
{
return(i + j);
}
int main()
{
std::cout << add() << ","; // 실매개변수 없음, 3
std::cout << add(10) << ","; // 실매개변수 한 개, 12
std::cout << add(10, 20); // 실매개변수 두개, 30
return 0;
}
형식매개변수 옆에 값을 준다면 디폴트 매개변수가 된다.
실매개변수가 없더라도 리턴값을 반환할 수 있게 된다.


#include <iostream>
int add(int i = 1, int j = 2) // 형식매개변수
{
return(i + j);
}
int main()
{
std::cout << add() << ","; // 실매개변수 없음, 3
std::cout << add(10) << ","; // 실매개변수 한 개, 12
std::cout << add(10, 20); // 실매개변수 두개, 30
return 0;
}
int add(int i, int j) {
return(i + j);
}
만약 위 소스에서 int main부분 아래 int add에서 int i = 1, int j = 2라고 수정 했을 때 오류가 나 실행이 되지 않는다. 정의부에는 작성하면 안되기 때문이다.
#include <iostream>
class Dog {
private:
int age;//멤버변수 추가
public:
Dog(int a = 1);
// Dog();
// Dog(int a);
~Dog();
int getAge();
void setAge(int a);
};
Dog::Dog(int a) { age = a; }
//Dog::Dog() { age = 1; }
//Dog::Dog(int a) { age = a; }
Dog::~Dog() { std::cout << "bye!\n"; }
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; }
int main()
{
Dog coco, happy(5);
// coco.setAge(3); // 나이 지정하기
std::cout << coco.getAge() << std::endl; // coco.getAge 만들기
std::cout << happy.getAge() << std::endl; // happy의 나이 출력하기
return 0;
}
새롭게 디폴트 매개변수를 선언한 코드다.
이름까지 저장할 수 있는 클래스
1단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
int getAge() { return age; }
void setAge(int a) { age = a; }
};
int main()
{
return 0;
}
2단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
};
int main()
{
return 0;
}
age = a를 this -> age = age;로 변경
3단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
std::string getname() { return name; }
void setname(std::string name) { this -> name = name; }
};
int main()
{
return 0;
}
4단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
std::string getName() { return name; }
void setName(std::string name) { this -> name = name; }
};
int main()
{
Dog coco;
coco.setName("코코");
coco.setAge(1);
std::cout << coco.getName() << coco.getAge();
return 0;
}
인스턴스를 만들어 나이와 이름을 입력해 출력해보는 결과
5단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
Dog() { age = 1; name = "강아지"; }
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
std::string getName() { return name; }
void setName(std::string name) { this -> name = name; }
};
int main()
{
Dog coco,happy;
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
coco.setName("코코");
coco.setAge(1);
happy.setName("해피");
happy.setAge(2);
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
return 0;
}

처음은 초기값이 없으니 디폴트값인 강아지, 1이 연속적으로 출력되어 강아지1 강아지1이 나오게 된다.
6단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
Dog() { age = 1; name = "강아지"; }
Dog(int a, std::string n) { age = a; name = n; }
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
std::string getName() { return name; }
void setName(std::string name) { this -> name = name; }
};
int main()
{
Dog coco,happy(3, "해피");
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
coco.setName("코코");
coco.setAge(1);
happy.setName("해피");
happy.setAge(2);
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
return 0;
}
생성자를 하나 더 추가해 해피의 이름과 나이를 바로 출력하게 할 수 있다.
7단계
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
// Dog() { age = 1; name = "강아지"; }
Dog(int a=1, std::string n="강아지") { age = a; name = n; }
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
std::string getName() { return name; }
void setName(std::string name) { this -> name = name; }
};
int main()
{
Dog coco,happy(3, "해피");
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
coco.setName("코코");
coco.setAge(1);
happy.setName("해피");
happy.setAge(2);
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
return 0;
}
public에 첫줄을 주석처리한다고해도 int a를 int a = 1, std::string n을 std::string n="강아지"로 바꿀 수 있다.
Dog(int age=1, std::string name="강아지") { this -> age = age; this -> name = name; }
int a를 int age로 바꾸고 std::string n을 std::string name으로 바꾸고 this를 추가해주는게 더 좋다.
std::string getName() const { return name; }
const를 붙여주면 더 좋다.
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
// Dog() { age = 1; name = "강아지"; }
Dog(int age=1, std::string name="강아지") { this -> age = age; this -> name = name; }
int getAge() { return age; }
void setAge(int age) {this -> age = age; }
std::string getName() const { return name; }
void setName(std::string name) { this -> name = name; }
};
int Dog::getAge() { return age; }
void Dog::setAge(int age) { this->age = age; }
std::string Dog::getName() const { return name; }
void Dog::setName(std::string name) { this->name = name; }
int main()
{
Dog coco,happy(3, "해피");
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
coco.setName("코코");
coco.setAge(1);
happy.setName("해피");
happy.setAge(2);
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
return 0;
}
밖으로 빼서 써줄 수 있다.
#include <iostream>
class Dog {
private:
int age;
std::string name;
public:
// Dog() { age = 1; name = "강아지"; }
Dog(int age = 1, std::string name = "강아지");
int getAge() const;
void setAge(int age);
std::string getName() const;
void setName(std::string name);
};
Dog::Dog(int age, std::string name) { this->age = age; this->name = name; }
int Dog::getAge() const { return age; }
void Dog::setAge(int age) { this->age = age; }
std::string Dog::getName() const { return name; }
void Dog::setName(std::string name) { this->name = name; }
int main()
{
Dog coco,happy(3, "해피");
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
coco.setName("코코");
coco.setAge(1);
happy.setName("해피");
happy.setAge(2);
std::cout << coco.getName() << coco.getAge() << std::endl;
std::cout << happy.getName() << happy.getAge() << std::endl;
return 0;
}
최종 완성형이라고 볼 수 있다. const를 함수에 써주고 생성자를 public밖으로 꺼내어 작성했다.