C++

11. 함수 중첩, 디폴트 인자

리버윤 2024. 11. 12. 11:01
728x90
Chat gpt. 객체지향언어의 4가지 대표적인 특징을 알려줘
  1. 캡슐화 (Encapsulation) : 데이터와 그 데이터를 처리하는 메서드를 하나의 단위로 묶어 외부에서 직접 접근하지 못하도록 보호하는 개념입니다. 이를 통해 데이터의 안전성을 높이고, 코드의 유지보수를 용이하게 합니다.
  2. 상속 (Inheritance) : 기존 클래스(부모 클래스)의 속성과 메서드를 새로운 클래스(자식 클래스)가 물려받는 기능입니다. 이를 통해 코드의 재사용성을 높이고, 계층 구조를 만들 수 있습니다.
  3. 다형성 (Polymorphism) : 동일한 인터페이스를 통해 서로 다른 클래스의 객체를 처리할 수 있는 능력입니다. 메서드 오버로딩과 메서드 오버라이딩을 통해 구현되며, 프로그램의 유연성을 증가시킵니다.
  4. 추상화 (Abstraction) : 복잡한 시스템에서 필요한 부분만을 모델링하여 단순화하는 과정입니다. 객체의 속성과 행동을 정의하고, 불필요한 세부 사항은 감추어 사용자가 쉽게 이해하고 사용할 수 있도록 합니다.

 

프로그래밍 언어에서 (), {}, [], <> 의 용도를 알려줘
  • ( ) (괄호) : 함수 호출 시 매개변수를 전달할 때 사용합니다. 예: functionName(arg1, arg2).
    수학적 표현의 우선순위를 지정할 때 사용합니다. 예: result = (a + b) * c.
    조건문이나 반복문에서 조건을 그룹화할 때도 사용합니다. 예: if (condition) { ... }.
  • { } (중괄호) : 코드 블록을 정의하는 데 사용합니다. 예를 들어, 함수, 조건문, 반복문의 몸체를 감쌀 때 사용합니다. 예: if (condition) { ... }.
    객체 리터럴을 정의할 때도 사용됩니다. 예: let obj = { key: value };.
    클래스 정의 시에도 사용됩니다. 예: class MyClass { ... };.
  • [ ] (대괄호) : 배열이나 리스트를 정의하고 접근할 때 사용합니다. 예: array[index].
    리스트, 벡터 등 다양한 자료구조를 표현하는 데 사용됩니다. 예: std::vector<int> vec;.
    인덱스 연산자를 사용할 때도 사용됩니다. 예: list[0] = value;.
  • < > (각괄호) : 제네릭 타입을 정의할 때 사용합니다. 예: List<String> list;.
    HTML/XML과 같은 마크업 언어에서 태그를 정의할 때 사용됩니다. 예: <tag>content</tag>.
    C++ 템플릿 인스턴스화 시에도 사용됩니다. 예: template<typename T> class MyClass;.

 

 

- C++에서 다형성의 종류

 

 

1. 함수 오버로딩(중첩, function overloading)

  • 다형성을 구현하는 한가지 방법
  • 하나의 함수명을 여러 개의 유사 목적으로 사용할 수 있다.
    • C의 경우 함수 중첩 불가능

- 함수 중첩 예제

#include <iostream>

int add(int i, int j)
{
	return (i + j);
}
double add(double i, double j)
{
	return (i + j);
}
int main()
{
	std::cout << add(10, 20) << std::endl;
	std::cout << add(10.5, 20.3) << std::endl;
	return 0;
}

 

 

- 함수 중첩이 불가능한 경우

#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;
}

 

ctrl + m + o :코드 접기

ctrl + m + l : 코드 펼치기

 

- 매개변서의 형이 다른 오버로딩

#include <iostream>
int Max(int i, int j) //소문자 max는 이미 있는거라 대문자로
{
	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>
int add(int i, int 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, 2, 3) << std::endl;
	std::cout << add(1, 2, 3, 4) << std::endl;
	return 0;
} //오버로딩 안함

 

▶ 함수중첩을 하는 2가지 경우

  • 매개변수의 형이 다른 경우
  • 매개변수의 개수가 다른 경우

 

▶ 생성자 중첩

  • 클래스의 멤버함수도 중첩이 가능하고, 생성자도 물론 중첩 가능
  • But, 소멸자는 중첩 불가능
  • 생성자에 함수를 중첩시키는 것은 객체에 초기값을 다양하게 주는 선택 기회를 제공하는 것

- 1단계

#include <iostream>

class Dog {  //1단계

};
int main()
{
	
	return 0;
}

 

- 2단계

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
};
int main()
{
	
	return 0;
}

 

- 3단계

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
public:
	getAge() {
		
	}
	setAge() {

	} // 3단계, 입출력함수 만들기
};
int main()
{
	
	return 0;
}

 

- 4단계

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} // 3단계, 입출력함수 만들기
};
int main()
{
	
	return 0;
}

 

- 5단계

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} // 3단계, 입출력함수 만들기
};
int main()
{
	Dog coco;
	std::cout << coco.getAge(); // 쓰레기값 출력됨
	return 0;
}

 

- 6단계

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} // 3단계, 입출력함수 만들기
};
int main()
{
	Dog coco;
	coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge(); // 쓰레기값 출력됨
	return 0;
}

 

- 7단계 (생성자)

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} // 3단계, 입출력함수 만들기
	
	Dog() {  //생성자. 클래스 이름과 같음

	}
};
int main()
{
	Dog coco;
	coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge(); // 쓰레기값 출력됨
	return 0;
}

 

- 8단계

#include <iostream>

class Dog {  //1단계, class 생성
private:
	int age; //2단계, 멤버변수 만들기
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} // 3단계, 입출력함수 만들기
	
	Dog() {  //생성자. 클래스 이름과 같음
		age = 1;
	}
};
int main()
{
	Dog coco;
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge(); // 1출력
	return 0;
}

 

- 9단계

#include <iostream>

class Dog { 
private:
	int age;
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} 
	
	Dog() {  //생성자. 클래스 이름과 같음
		age = 1;
	}
	Dog(int a) {  //생성자 함수 중첩
		age = a;
	}
};
int main()
{
	Dog coco, happy(5);
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge() << std::endl;
	std::cout << happy.getAge() << std::endl;
	return 0;
}

 

- 10단계(소멸자)

#include <iostream>

class Dog { 
private:
	int age;
public:
	int getAge() {
		return age;
	}
	void setAge(int a) {
		age = a;
	} 
	
	Dog() { 
		age = 1;
	}
	Dog(int a) { 
		age = a;
	}

	~Dog() {  //소멸자, 종료되면서 자동으로 출력
		std::cout << "bye~~ \n";
	}
};
int main()
{
	Dog coco, happy(5);
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge() << std::endl;
	std::cout << happy.getAge() << std::endl;
	return 0;
}

 

- 11단게

#include <iostream>

class Dog { 
private:
	int age;
public:
	int getAge() { return age; }
	void setAge(int a) { age = a; } 
	
	Dog() { age = 1; }
	Dog(int a) { age = a; }

	~Dog() { std::cout << "bye~~ \n"; }
};
//밖으로 끄집어내기
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; }  //Dog:: 위치 주의

Dog::Dog() { age = 1; }
Dog::Dog(int a) { age = a; }

Dog::~Dog() { std::cout << "bye~~ \n"; }


int main()
{
	Dog coco, happy(5);
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge() << std::endl;
	std::cout << happy.getAge() << std::endl;
	return 0;
}

 

- 12단계

#include <iostream>

class Dog { 
private:
	int age;
public:
	int getAge();
	void setAge(int a);
	Dog();  //생성자
	Dog(int a);  //생성자
	~Dog();  //소멸자
};
//밖으로 끄집어내기
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; }  //Dog:: 위치 주의
Dog::Dog() { age = 1; }
Dog::Dog(int a) { age = a; }
Dog::~Dog() { std::cout << "bye~~ \n"; }


int main()
{
	Dog coco, happy(5);
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge() << std::endl;
	std::cout << happy.getAge() << std::endl;
	return 0;
}

 

 

- 생성자 중첩 예

#include <iostream>
using std::cout;
using std::endl;
class Dog {
private:
	int age;
public:
	Dog() { age = 1; }
	// 매개변수가 없는 생성자
	Dog(int a) { age = a; }
	// 매개변수가 하나인 생성자
	~Dog();
	int getAge();
	void setAge(int a);
};

Dog::~Dog() { std::cout << "소멸\n"; }
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; } 

int main()
{
	Dog happy[5];
	Dog meri[5] = { 1,2,3,4,5 };
	for (int i = 0; i < 5; i++)
		std::cout << happy[i].getAge() <<
		"," << meri[i].getAge() << std::endl;
	return 0;
}

 

2. 디폴트 인자(default parameter, default argument)

  • 디폴트 매개변수
  • C++에서는 함수를 호출할 때 별도의 매개변수를 전달하지 않아도 기본적인 값을 전달하도록 함수 원형을 선언할 때 디폴트 값을 지정할 수 있다.
  • 디폴트 매개변수의 사용은 함수 중첩을 축약형
  • 디폴트 매개변수를 정의하기 시작하면 그 다음의 매개변수들은 모두 디폴트 매개변수를 기져야 함
    • int add(int i=1, int j=2);
    • int add(int i, int j=2); //이건 가능
    • int add(int i=1, int j); //오류 발생
#include <iostream>
int add(int i, int j) // 형식매개변수
{
	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) // 형식매개변수, 2개가 넘어와야하는데 안넘어온다면 저 값을 쓰겠다는 것
{
	return(i + j);
}
int main()
{
	std::cout << add() << ","; // 실매개변수 없음, 3
	std::cout << add(10) << ","; // 실매개변수 한 개, 12
	std::cout << add(10, 20); // 실매개변수 두개, 30
	return 0;
}

  2개가 넘어와야하는데 안넘어온다면 저 값을 쓰겠다는 것

#include <iostream>
int add(int i, int j=1) // 형식매개변수
{
	return(i + j);
}
int main()
{
	//std::cout << add() << ","; // 실매개변수 없음, 
	std::cout << add(10) << ","; // 실매개변수 한 개, 11
	std::cout << add(10, 20); // 실매개변수 두개, 30
	return 0;
}

 

 

※ 선언과 정의를 나눴을 때는 선언부에만 디폴트 값 작성. 정의부에는 작성하지 않는다.

#include <iostream>
int add(int i = 1, int j = 2); //선언, 선언부에만 디폴트 작성
int main()
{
	//std::cout << add() << ","; // 실매개변수 없음, 
	std::cout << add(10) << ","; // 실매개변수 한 개, 11
	std::cout << add(10, 20); // 실매개변수 두개, 30
	return 0;
}
int add(int i, int j) //정의
{
	return(i + j);
}

 

 

#include <iostream>

class Dog {
private:
	int age;
public:
	int getAge();
	void setAge(int a);
	//Dog();
	//Dog(int a);
	~Dog();
	Dog(int a=1) { age = a; } 
};
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; }  //Dog:: 위치 주의
//Dog::Dog() { age = 1; }
//Dog::Dog(int a) { age = a; }
Dog::~Dog() { std::cout << "bye~~ \n"; }


int main()
{
	Dog coco, happy(5);
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge() << std::endl;
	std::cout << happy.getAge() << std::endl;
	return 0;
}
#include <iostream>

class Dog {
private:
	int age;
public:
	int getAge();
	void setAge(int a);
	//Dog();
	//Dog(int a);
	~Dog();
	Dog(int a = 1);  //디폴드 값은 여기 선언에만 작성
};
int Dog::getAge() { return age; }
void Dog::setAge(int a) { age = a; }  //Dog:: 위치 주의
//Dog::Dog() { age = 1; }
//Dog::Dog(int a) { age = a; }
Dog::~Dog() { std::cout << "bye~~ \n"; }
Dog::Dog(int a) { age = a; }


int main()
{
	Dog coco, happy(5);
	//coco.setAge(3); //나이 입력하고 출력
	std::cout << coco.getAge() << std::endl;
	std::cout << happy.getAge() << std::endl;
	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 a) { this -> age = age; }
	std::string getName() { return name; }
	void setName(std::string n) { this -> name = name; }
};

int main()
{

	return 0;
}

 

- 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()
{
	Dog coco;
	coco.setName("코코");
	coco.setAge(1);
	std::cout << coco.getName() << coco.getAge();
	return 0;
}

 

-4단계 (생성자)

#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;  //강아지 1
 	std::cout << happy.getName() << happy.getAge() << std::endl; //강아지 1

	coco.setName("코코");
	coco.setAge(1);

	std::cout << coco.getName() << coco.getAge() << std::endl; // 코코 1
	std::cout << happy.getName() << happy.getAge() << std::endl; //강아지 1

	return 0;
}

 

-5단계

#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;  //강아지 1
 	std::cout << happy.getName() << happy.getAge() << std::endl; //해피 3

	coco.setName("코코");
	coco.setAge(1);

	std::cout << coco.getName() << coco.getAge() << std::endl; // 코코 1
	std::cout << happy.getName() << happy.getAge() << std::endl; //해피3

	return 0;
}

 

- 6단계

#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;  //강아지 1
 	std::cout << happy.getName() << happy.getAge() << std::endl; //해피 3

	coco.setName("코코");
	coco.setAge(1);

	std::cout << coco.getName() << coco.getAge() << std::endl; // 코코 1
	std::cout << happy.getName() << happy.getAge() << std::endl; //해피3

	return 0;
}

 

-7단계

#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() { return name; }
	void setName(std::string name) { this -> name = name; }
};

int main()
{
	Dog coco, happy(3, "해피");
	std::cout << coco.getName() << coco.getAge() << std::endl;  //강아지 1
 	std::cout << happy.getName() << happy.getAge() << std::endl; //해피 3

	coco.setName("코코");
	coco.setAge(1);

	std::cout << coco.getName() << coco.getAge() << std::endl; // 코코 1
	std::cout << happy.getName() << happy.getAge() << std::endl; //해피3

	return 0;
}

 

-8단계 (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() const { return age; }
	void setAge(int age) { this -> age = age; }
	std::string getName() const { return name; }
	void setName(std::string name) { this -> name = name; }
};

int main()
{
	Dog coco, happy(3, "해피");
	std::cout << coco.getName() << coco.getAge() << std::endl;  //강아지 1
 	std::cout << happy.getName() << happy.getAge() << std::endl; //해피 3

	coco.setName("코코");
	coco.setAge(1);

	std::cout << coco.getName() << coco.getAge() << std::endl; // 코코 1
	std::cout << happy.getName() << happy.getAge() << std::endl; //해피3

	return 0;
}

 

-  최종 밖으로 빼내는 수정

#include <iostream> // 입출력 스트림 라이브러리 포함

class Dog { // Dog 클래스를 정의
private:
    int age; // 개의 나이를 저장하는 private 변수
    std::string name; // 개의 이름을 저장하는 private 변수
public:
    // 기본 매개변수를 갖는 생성자 선언
    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; // 매개변수 age를 클래스의 age 변수에 할당
    this->name = name; // 매개변수 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; // 기본 생성자를 사용하여 coco 객체 생성 (age=1, name="강아지")
    Dog happy(3, "해피"); // 매개변수를 사용하여 happy 객체 생성 (age=3, name="해피")
    
    // coco 객체의 이름과 나이를 출력 (강아지 1)
    std::cout << coco.getName() << coco.getAge() << std::endl;  
    // happy 객체의 이름과 나이를 출력 (해피 3)
    std::cout << happy.getName() << happy.getAge() << std::endl; 

    coco.setName("코코"); // coco 객체의 이름을 "코코"로 변경
    coco.setAge(1); // coco 객체의 나이를 1로 설정 (변경 없음, 이미 1)

    // coco 객체의 이름과 나이를 출력 (코코 1)
    std::cout << coco.getName() << coco.getAge() << std::endl; 
    // happy 객체의 이름과 나이를 출력 (해피 3)
    std::cout << happy.getName() << happy.getAge() << std::endl; 

    return 0; // 프로그램 정상 종료
}
728x90