괄호가 입력되면 올바른 괄호이면 “YES", 올바르지 않으면 ”NO"를 출력한다.

 

()의 법칙을 생각하자. )가 먼저 나올수 없고 )의 숫자가 더 많을 수 없다.

미리 머리속에 그려보자.

 

힌트 : 숫자를 기준으로 생각하자.

법칙을 생각해보자.

 

#include <stdio.h>

using namespace std;

int main(int argc, char** argv) {
	//freopen("input.txt", "rt", stdin);
	char a[30];
	gets(a);
	
	int  p = 0;
	int  p2 = 0;
	bool b = true;
	for (int i = 0; a[i] != '\0'; i++) {
	
		if(a[i]==40){
			p++;
		}else if(a[i]==41){
			p--;
		}
		
		if(p < 0){
			break;
		}
	}
	
	if(p  == 0){
		printf("%s","YES");
	}else{
		printf("%s","NO");
	}
	return 0;
}
#include <stdio.h>

using namespace std;

int main(int argc, char** argv) {
	freopen("input.txt", "rt", stdin);
	char a[101],b[101];
	gets(a);
	
	int  p = 0;
	for (int i = 0; a[i] != '\0'; i++) {
		//printf("%d\n", a[i]);
		if (a[i] != 32) {
			if (a[i] >= 65 && a[i] <= 90) {
				//printf("%c", a[i] + 32);
				b[p++] = a[i]+32;
			}
			else if(a[i] >= 97 && a[i] <= 122){
				//printf("%c", a[i]);
				b[p++] = a[i];
			}
		}
	}
	
	b[p] = '\0';
	printf("%s",b);	
	return 0;
}

영어단어가 뛰어쓰기와 대소문자가 혼합되어 표현된다.

뛰어쓰기를 제거하고 소문자로 단어를 출력해보자.

 

1.gets로 문자열을 받아온다.(scanf는 뛰어쓰기에서 멈춘다.)

2.문자열을 확인후 뛰어쓰기는 거른다.

3.대문자는 소문자로 변경한다.

 

힌트: 대문자의 아스키코드 65-90이다.

 

 

문자와 숫자가 섞여있는 문자열이 주어지면 그 중 숫자만 추출하여

그 순서대로 자연수를 만 듭니다.

만들어진 자연수와 그 자연수의 약수 개수를 출력합니다.

 

1.문자열을 입력받거나 읽어온다.

2.문자열에서 숫자만 추출한다.

3.추출된 숫자의 약수를 구한다.

 

힌트: 0~9는 아스키코드 48~57이다.

숫자가 더해질때마다 십의 자리가 증가한다.

 

#include <stdio.h>

using namespace std;

int main(int argc, char** argv) {
	//freopen("input.txt", "rt", stdin);
	char a[100];
	scanf("%s", &a);

	int res = 0, cnt=0;

	for(int i = 0; a[i] !='\0'; i++){
		if(a[i] >= 48 && a[i] <= 57){
			res = res*10+(a[i]-48);
		}
	}
	
	printf("%d\n",res);
	for(int i = 1; i <= res; i++){
		if(res%i == 0){
			cnt ++;
		}
	}
	printf("%d\n",cnt);
	return 0;
}

자연수 N이 주어지면 자연수 N의 진약수의 합을 수식과 함께 출력하는 프로그램을 작성하기.

 

진약수란? 특정숫자를 나누었을때 나머지가 0이 되는 숫자를 말한다.

 

1. N값을 입력받는다.

2. 1부터 N의 진약수를 알아보고 출력한다.

1 + x + x + x + x = x 형식으로 출력하기

 

힌트 : 1은 무조건 진약수이므로 미리 출력해도 된다.

 

#include <iostream>

using namespace std;

int main(int argc, char** argv) {
	int n, i = 2,sum = 1;
	cin >> n;

	cout << "1";

	for (i; i < n; i++) {
		if(n%i == 0){
			cout << " + "<<i ;
			sum += i;
		}
		
	}
	cout << " = "<<sum;
	return 0;
}

자연수 N이 입력되면 1부터 N까지의 수 중 M의 배수합을 출력하는 프로그램을 작성한다.

 

N,M을 입력받고 1~N까지 숫자중에 M의 배수들의 합을 구해보자.

 

기초적인 문제 N,M을 입력받는 코드를 작성한다.

1부터 N까지 반복문을 작성하고 그안에 M의 배수를 확인하는 조건문을 작성한다.

조건에 맞는 수를 sum변수에 넣어준다.

#include <iostream>

using namespace std;

int main(int argc, char** argv) {
	int n, m, i = 0, sum = 0;
	cin >> n;
	cin >> m;

	for (i; i <= n; i++) {
		if (i%m == 0) {
			sum += i;
		}
	}
	cout << sum;
	return 0;
}

상속받은 함수를 오버라이딩하기

상속을 사용하는 일반적인 경우엔

상속을 해주는 부모클래스와 상속을 받는 자식클래스는
보통 기능차이가 많지않을 수 있다.

이때 함수오버라이딩을 유용하게 사용할수 있다.

함수 오버라이딩할때 부모클래스의 함수를 사용하고 싶다면 부모클래스이름은 선언한다.

Base::Print();


다형성에서 사용된다.

<< operator 를 사용하고 싶으면 static_cast해서 사용한다.

out << static_cast<Base>(b) << endl;

 

#include <iostream>

using namespace std;

class Base {
protected:
	int m_i;

public:
	Base(int a)
		: m_i(a)
	{

	}

	void Print() {
		cout << "I'm  Base" << endl;
	}

	friend std::ostream & operator << (std::ostream & out, const Base &b) {
		out << "Base opertator";
		return out;
	}
};

class Derived : public Base {
public:
	double m_d;

	Derived(int a)
		:Base(a) {

	}

	void Print() {
		Base::Print();
		cout << "I'm  Derived" << endl;
	}

	friend std::ostream & operator << (std::ostream & out, const Derived &b) {
		out << static_cast<Base>(b) << endl;
		out << "Derived opertator";
		return out;
	}
};

int main()
{
	Base b(5);
	Derived d(2);

	b.Print();
	d.Print();
	cout << b << endl;
	cout << d << endl;
	return 0;
}

상속과 접근지정자

클래스에서 접근지정자로 접근권한을 제한할 수 있다.
상속도 마찬가지로 접근지정자로 제어할 수 있다.

protected는 외부에선 접근 불가능하지만 자식클래스에서 접근가능하다.

유도된 클래스(자식클래스)에 새로운 기능 추가할때
protected를 사용하면 private 변수일때 public에 getValue()를 만들어 사용하지않고 퍼포먼스를 향상시킬 수 있다.

 

#include <iostream>
using namespace std;
class Base {
protected:
	int m_public;

public:
	Base(const int & a) 
	:m_public(a){

	}
};

class Derived : public Base
{
public:
	Derived(const int & a) 
	:Base(a){
	
	}

	void setValue(int value) {
		Base::m_public + value;
	}
};
int main()
{

	return 0;
}


다중상속일때 단계가 높은 부모클래스에 접근하지 못하게할때 사용한다.

즉, private 으로 상속하면 다중상속일때 하하위 클래스가 직접접근하지 못하게한다.

 

#include <iostream>

using namespace std;

class Base {
public:
	int m_public;

	int funPublic() {
		return 0;
	}
protected:
	int m_protected;
	int funProtected() {
		return 0;
	}
private:
	int m_private;
};

class Derived : public Base
{
public:
	Derived() {
		m_public = 123;
		m_protected = 123;
		//m_private = 123;
		funPublic();
		funProtected();
	}
};

class Derived2 : protected Base
{
public:
	int a;
	Derived2() {
		m_public = 123;
		m_protected = 123;
		//m_private = 123;
		a = funPublic();
		a = funProtected();
	}
protected:
	int a2 = 0;
};

class Derived3 : private Base
{
public:
	int a;

	Derived3() {
		m_public = 123;
		m_protected = 123;
		//m_private = 123;
		a = funPublic();
		a = funProtected();
	}

};

class GrandChild : public Derived3 {
public:
	GrandChild() {
		//m_public; 불가능하다
		cout << a << endl;
	}
};

int main()
{
	Derived der;

	der.m_public = 123;
	//base.m_protected = 123;
	//base.m_private = 123;
	
	//protected 상속
	Derived2 der2;
	//der.m_public = 123;

	//private 상속
	Derived3 der3;
	//der.m_public = 123;


	return 0;
}

유도된 클래스들의 생성과 초기화

부모클래스를 상속한 자식클래스의 크기를 보게되면
부모클래스의 크기까지 포함된걸 볼 수 있다.
sizeof로 확인한다. 패딩으로인해 정확한 사이즈는 안나온다.

다중상속을 하게됬을때 A > B > C 로 상속하게되면 C는 A의 생성자를 실행하지 못한다.

생성자는 부모부터 소멸자는 자식부터 실행된다. 잊지말자!

 

#include <iostream>

using namespace std;

class A
{
private:
	int m_i;

public:
	A(const int &a) :m_i(a) {
		cout << "A Constructor" << endl;
	}

	~A() {
		cout << "A Destructor" << endl;
	}

};

class B : public A
{
public:
	double m_d;
	B(const int & i, const double &b)
		: A(i), m_d(b) {
		cout << "B Constructor" << endl;
	}
	~B() {
		cout << "B Destructor" << endl;
	}
};

class C : public B
{
public:
	char m_c;
	C(const int & i, const double &b,const char & c)
		: B(i,b), m_c(c) {
		cout << "C Constructor" << endl;
	}
	~C() {
		cout << "C Destructor" << endl;
	}
};


int main()
{

	cout << sizeof(A) << endl;
	cout << sizeof(B) << endl;
	cout << sizeof(C) << endl;

	C c(1, 1.3, 'a');

	return 0;
}

유도된 클래스들의 생성순서
Derived

 

기본지식

접근지정자
private 은 자식도 사용못한다.
protected는 자식은 사용가능하다.

:initalizer list는 안된다. 이유는?
클래스가 생성되는 순서를 알아야한다.

자식클래스를 객체생성하면 부모클래스가 먼저 생성되는것을 확인할 수 있다.

debug를 해보게되면
부모객체,자식객체변수를 쓰레기값으로 생성되고 
부모객체부터 초기화하고 자식객체의 변수들을 초기화되는걸 볼 수 있다. 

자식클래스는 부모클래스에 있는걸 다 사용할 수 있기에
부모클래스부터 정의해서 사용할 수 있게한다.

부모클래스의 constructor를 항상 먼저 실행시킨다.

다중상속을 하여도 맨위의 부모클래스부터 연쇄적으로초기화한다.

소멸자 Destructor는 반대로 소멸된다. 자식부터 소멸된다.

 

아래코드의 생성 순서를 보자(주석으로 써놓았다.)

1.객체생성한다.

2. 자식클래스 생성자로 온다.

3.부모클래스 생성자를 실행한다.

4.자식클래스의 생성자를 초기화한다.

 

#include <iostream>

using namespace std;

class Mother
{
public:
	int m_i;
	//3.부모클래스 생성자를 실행한다.
	Mother() :m_i(1){
		cout << "Mother Constructor" << endl;
	}
	~Mother() {
		cout << "Mother Destructor" << endl;
	}
	Mother(const int &a) :m_i(a) {
		cout << "Mother Constructor" << endl;
	}
};

class Child : public Mother 
{
public:
	double m_d;
	//2. 자식클래스 생성자로 온다.
	Child()
	: //내부적으로 숨어있다.Mother(),
		//4.자식클래스의 생성자를 초기화한다.
		m_d(1.0){
		cout << "Child Constructor" << endl;
	}
	~Child() {
		cout << "Child Destructor" << endl;
	}
};


class A : public Child
{
public:
	A() {
		cout << "A" << endl;
	}
	~A() {
		cout << "A Destructor" << endl;
	}
};
int main()
{
	//1.객체생성
	Child c1;
	
	return 0;
}

Inheritance (is-a relationship)

상속이 도움되는 이유를 구체적인 사례를 보자.

학생,교수 클래스 모두 이름이 있다.
학생,교수의 공통점은 사람이다.

사람의 기본적인 데이터(이름)를 부모클래스로 생성한다.
즉, 중복되는 데이터만 부모클래스로 뽑아낸다.

부모클래스만 사용하는기능은 부모클래스에 정의한다.
set,get등이 있다.

부모클래스의 기능을 사용가능한건 this로 확인할 수 있다.

중복되는 기능을 유지보수할때 부모클래스만 수정하면되게된다.

 

아래코드는 교수,학생클래스를 생성할때 공통된 데이터인

이름을 부모클래스로 생성해 상속받는다.

 

Person.h

#pragma once
#include <string>
#include <iostream>

class Person 
{
private:
	std::string m_name;

public:
	Person(const std::string & name) 
	:m_name(name) {}

	void setName(const std::string & name) {
		m_name = name;
	}

	std::string getName() const{
		return m_name;
	}

	void doNothing() const
	{
		std::cout << m_name << " doNothing" << std::endl;
	}
};

Student.h

#pragma once

#include "Person.h"

class Student : public Person{
private:
	int m_intel;

public:
	Student(const std::string & name = "noName", const int & intel = 0)
		: Person(name), m_intel(intel) {}

	void setIntel(const int & intel) {
		m_intel = intel;
	}

	int getIntel()
	{
		return m_intel;
	}

	friend std::ostream & operator << (std::ostream & out, const Student & s) {
		out << s.getName() << " " << s.m_intel;
		return out;
	}
};

Teacher.h

#pragma once

#include "Person.h"

class Teacher :public Person
{
private:


public:
	Teacher(const std::string & name = "noName")
		:Person(name) {

	}

	friend std::ostream & operator << (std::ostream & out, const Teacher & t1) {
		out << t1.getName();
		return out;
	}

};

main.cpp

#include "Student.h"
#include "Teacher.h"

using namespace std;

int main()
{
	string name = "";
	Student s("Jack Jack");
	Teacher t("Choi");

	cout << s.getName() << endl;
	cout << t.getName() << endl;

	s.doNothing();
	t.doNothing();

	return 0;
}

+ Recent posts