728x90

참고 강의 : https://wikidocs.net/book/31

 

 

클래스

클래스는 객체를 생성하는 기능이 있다.

1
2
3
public class Animal {
 
}
cs

 

객체의 생성

1
Animal cat = new Animal();
cs

 

객체와 인스턴스의 차이

 

인스턴스 : 클래스에 의해서 만들어진 객체이며, 위에서 cat은 객체. 

cat이라는 객체는 Animal의 인스턴스(instance). 

 

즉, "cat은 인스턴스" 보다는 "cat은 객체" 이며, Animal의 객체가 아닌 "cat은 Animal의 인스턴스" 라고 표현한다.

 

 

붕어빵 틀은 클래스, 붕어빵 틀에 의해 만들어진 붕어빵 들은 객체

또는 Animal은 클래스이고 고양이와 개, 말 등은 객체

 

아래와 같이 Animal 클래스에서 무수히 많은 동물 객체들이 생성될 수 있다.

1
2
3
4
Animal cat = new Animal();
Animal dog = new Animal();
Animal horse = new Animal();
...
cs

 

 

Animal 클래스에 인스턴스 변수(또는 멤버변수나 속성) name을 추가

인스턴스 변수에 접근하려면 인스턴스.변수 와 같이 접근한다. (cat.name)

1
2
3
4
5
6
7
8
9
10
11
package jump2java;
 
public class Animal {
        String name;
    
    public static void main(String [] args){
        Animal cat = new Animal();
        System.out.println(cat.name);
    }
}
 
cs

 

Output :

null

 

 

값이 할당되지 않았기에 null이 출력된다.

 

 

 

특정 클래스가 있는 자바 파일 내에 또 다른 클래스 정의 가능
 * - 단, 원래 클래스가 아닌 다른 클래스들은 public 키워드를 붙일 수 없다!

 

 

Java의 메소드 

Java에서 클래스 내에 구현된 함수를 메소드라고 한다. 

(함수라는 용어를 쓰지 않으며, 클래스 내에서만 사용가능)

 

아래와 같이 return값이 없는 void 메소드를 정의해준다. 

return값이 없다는 거에 당황할 수 있지만 setName의 name은 메소드 내에서 할당되며 돌려주는 값은 없다.

 

 

this 키워드

아래의 코드에서 Animal 클래스의 인스턴스 변수명도 name, SetName 메소드의 인수도 name이다. (String name)

아래 예제에서 this는 Animal 클래스에 의해서 생성된 인스턴스를 가리키며,  cat을 가리킨다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package jump2java;
 
public class Animal {
        String name;
        
    public void setName(String name) {
        this.name = name;
    }
    
    public static void main(String [] args){
        Animal cat = new Animal();
        cat.setName("Ludwig");
        System.out.println(cat.name);
    }
}
cs

 

Output :

Ludwig

 

 

 

 

메소드 내에서만 쓰이는 지역 변수 (local variable)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package jump2java;
 
public class Test {
        String name;
        
        public void vartest(int a) {
            a++;
        }
 
        public static void main(String[] args) {
            int a = 1;
            Test myTest = new Test();
            myTest.vartest(a);
            System.out.println(a);
        }
}
 
cs

 

Output :

1

 

 

vartest 메소드의 인수 a는 메소드 안에서만 쓰이는 변수이며, 메소드 밖(main함수)의 변수 a가 아니다.

메소드에서 쓰이는 변수는 지역변수로 밖의 변수와는 상관없다.

 

위에서 vartest 메소드를 이용해 값을 증가시키려면 다음과 같이 쓴다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package jump2java;
 
public class Test {
        String name;
        
        public int vartest(int a) {
            a++;
            return a;
        }
 
        public static void main(String[] args) {
            int a = 1;
            Test myTest = new Test();
            a = myTest.vartest(a);
            System.out.println(a);
        }
}
 
cs

 

입력으로 들어온 값이 1만큼 증가해 return되며 2가 출력된다.

주의할 점은, 이 역시 vartest 메소드 안의 a 변수와 메소드 밖의 a 변수는 다른 것이다!

 

 

Call by value

 

메소드에 을 전달하는 것과 객체를 전달하는 것의 차이를 알 수 있는 예제이다.

다음은 메소드에 값을 전달하는 예제이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jump2java;
 
class updator {
    void update(int cnt) {
        cnt++;
    }
}
 
public class Counter {
    int count = 0;
 
    public static void main(String[] args) {
        Counter myCounter = new Counter();
        System.out.println(" 초기 값 " + myCounter.count);
        updator myUpdator = new updator();
        myUpdator.update(myCounter.count);
        System.out.println(" update 값 " + myCounter.count);        
    }
}
cs

Output : 

 초기 값 0

 update 값 0

 

위의 예제는 값이 바뀌지 않음을 알 수 있다. update 메소드는 값을 전달받았으며, cnt 변수는 메소드 안에서만 쓰이는 변수이기 때문이다.

 

아래 예제는 객체를 전달해서 객체의 속성 값을 변경하도록 한 예제이다. 

위와 같이 int cnt로 값을 전달받는 것이 아니라 Counter cnt 와 같이 객체를 전달받도록 했다. (Counter 자료형 변수 cnt를 입력받아 증가시킴)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package jump2java;
 
class updator {
    void update(Counter cnt) {
        cnt.count++;
    }
}
 
public class Counter {
    int count = 0;
 
    public static void main(String[] args) {
        Counter myCounter = new Counter();
        System.out.println(" 초기 값 " + myCounter.count);
        updator myUpdator = new updator();
        myUpdator.update(myCounter);
        System.out.println(" update 값 " + myCounter.count);        
    }
}
cs

Output:

초기 값 0

update 값 1

 

 

자바에서의 상속

 

자바에서는 클래스 상속을 위해서 extends 키워드를 사용한다. Dog 클래스가 Animal 클래스를 상속함 (물려받음)

1
2
3
public class Dog extends Animal {
 
}
cs

 

먼저 프로젝트에서 Animal 클래스와 Dog 클래스를 생성한다.

 

Animal.java

1
2
3
4
5
6
7
8
9
10
11
12
13
package jump2java;
 
public class Animal {
    String name;
    
    public void setName(String name) {
        this.name = name;
    }
 
    public static void main(String[] args) {
        
    }
}
cs

 

Dog.java

1
2
3
4
5
6
7
8
9
10
package jump2java;
 
public class Dog extends Animal {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("Ludwig");
        
        System.out.println(dog.name);
    }
}
cs

Output :

Ludwig

 

Dog 클래스에서는 setName 메소드를 정의하지 않았지만, Animal 클래스를 상속했으므로 setName 메소드를 그대로 사용할 수 있다.

 

 

Dog.java에 bark 메소드를 하나 추가해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package jump2java;
 
public class Dog extends Animal {
    public void bark() {
        System.out.println(this.name + "은 멍 멍! 하고 짖었다!");
    }
    
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("Ludwig");
        
        System.out.println(dog.name);
        dog.bark();
    }
}
cs

 

Output :

Ludwig

Ludwig은 멍 멍! 하고 짖었다!

 

 

메소드 오버라이딩 

 

HouseDog.java

 

아래와 같이 HouseDog 클래스에 Dog 클래스와 동일한 원형의 bark 메소드를 구현하였다.

1
2
3
4
5
6
7
8
9
10
11
12
13
package jump2java;
 
public class HouseDog extends Dog {
    public void bark() {
        System.out.println(this.name + "는 도둑을 보면 짖는다");
    }
    
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        houseDog.setName("Toni");
        houseDog.bark();
    }
}
cs

Output (HouseDog.java에서 실행결과) : 

Toni는 도둑을 보면 짖는다

 
부모클래스의 메소드를 자식클래스가 동일한 원형으로 정의했지만, HouseDog 클래스에서 bark 메소드는 Dog 클래스의 bark 메소드보다 더 높은 우선순위를 갖게 된다. 그 결과, HouseDog 클래스의 bark 메소드가 호출되고 위와 같은 결과가 나온다.

 

이렇게 부모 클래스의 메소드를 자식 클래스가 동일한 원형을 가지고 재정의 하는 행위를 Method Overriding(메소드 덮어씌우기)이라고 한다. 

 

 

자바는 다중상속을 지원하지 않는다

다중상속의 모호함 때문에 자바는 일반 클래스의 다중상속을 지원하지 않는다. 

 

 

생성자

HouseDog클래스로 만든 인스턴스에 setName 메소드를 생성하지 않으면, name 인스턴스 변수에 값이 할당되지 않았기에 null이 출력된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package jump2java;
 
public class HouseDog extends Dog {
    public void bark() {
        
        System.out.println(this.name + "은(는) 도둑을 보면 짖는다");
    }    
    
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        //houseDog.setName("Toni");        
        houseDog.bark();
    }
}
cs

Output :

null은(는) 도둑을 보면 짖는다

 

 

생성자(Constructor)를 이용하면 name 이라는 인스턴스 변수를 무조건 초기화하도록 강제할 수 있다.

아래 소스에서 public HouseDog(String name) { ... 과 같이 메소드명이 클래스명과 동일하고 반환형이 없는 메소드가 생성자이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
package jump2java;
 
public class HouseDog extends Dog {
    public HouseDog(String name) {
        this.setName(name);
    }
    
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog();
        System.out.println(houseDog.name);
    }
}
cs
Output :
Exception in thread "main" java.lang.Error: 분석되지 않는 컴파일 문제점: 
생성자 HouseDog()이(가) 정의되지 않았습니다.
 
at jump2java.HouseDog.main(HouseDog.java:9)
 

생성자의 규칙대로 객체를 선언하지 않았기 때문에 컴파일 오류가 발생한다. (String변수로 값을 전달해 setName메소드 호출)

위의 소스 9번째 줄을 다음과 같이 변경해주면 정상적으로 컴파일되고 실행결과를 출력한다.

 

9
HouseDog houseDog = new HouseDog("Toni");
cs

Output :

Toni

 

 

생성자의 규칙

  1. 클래스명과 메소드명이 동일하다.
  2. 리턴타입을 정의하지 않는다.

 

default 생성자

1
2
3
4
5
6
7
8
public class Dog extends Animal {
    public Dog() {
    }
 
    public void sleep() {
        System.out.println(this.name + " zzz");
    }
}
cs

만약 생성자를 정의하지 않았다면 public Dog() {    } 와 같은 default 생성자를 컴파일러가 자동 생성한다.

생성자를 정의한다면 컴파일러는 따로 생성자를 만들지 않고, 그 생성자의 정의대로만 객체를 선언할 수 있다.

 

생성자 오버로딩

하나의 클래스에 다음과 같이 입력항목(인수)이 다른 여러개의 생성자를 만들 수 있다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package jump2java;
 
public class HouseDog extends Dog {
    public HouseDog(String name) {
        this.setName(name);
    }
 
    public HouseDog(char type) {
        if (type == 'm') {
            this.setName("Steve");
        } else if (type == 'f') {
            this.setName("Stephanie");
        }
    }
 
    public static void main(String[] args) {
        HouseDog houseDog = new HouseDog("Toni");
        System.out.println(houseDog.name);
        HouseDog male = new HouseDog('m');
        HouseDog female = new HouseDog('f');
        System.out.println(male.name);
        System.out.println(female.name);
    }
}
cs

 

Output :

Toni

Steve

Stephanie

 

위의 소스에서 HouseDog 클래스는 두 개의 생성자를 갖는다. 하나는 String type, 하나는 char type을 입력으로 받는 생성자이다.

메소드 오버로딩과도 비슷한 개념이다. 단, 메소드 오버로딩은 반환형은 반드시 일치해야 함에 유의!

 

오버로딩 시 시그니처가 같다면 오버로딩할 수 없다.

시그니처란 매개변수의 리스트를 가리키며 매개변수의 개수와 타입, 그 순서까지 모두 같다면 시그니처가 같다.

리턴값만 다를 경우 오버로딩이 성립되지 않는다.

 

그리고 오버로딩과 오버라이딩은 완전히 다른 개념이다.  

'Study > Java' 카테고리의 다른 글

Java Network 프로그래밍 기초  (0) 2017.06.03
NIO 기반 네트워킹  (0) 2017.05.30
JAVA - NIO  (0) 2017.05.29
Java - OOP_인터페이스와 다형성  (0) 2017.03.20
Java 개발PC 설정 및 기초  (0) 2017.03.16
728x90

참고 강의 : https://wikidocs.net/book/31


JDK 다운로드 : 

http://www.oracle.com/technetwork/java/javase/downloads/index.html?ssSourceSiteId=otnjp/


JDK 다운로드 시 오픈소스인 8 버전을 받는다


자바의 소스코드 파일명은 *.java 

이것을 컴파일하면 *.class 파일이 생성되며 Java VM이 class 파일의 바이너리 코드를 해석해 실행한다.


JVM은 이란 중간 단계를 거치기 때문에 속도면에선 단점이 있지만 모든 OS에서 실행가능한 장점을 가진다.



javac (Compiler) 확인 

: 콘솔에서 javac 실행


참고 : 주석은 프로그램 실행과는 상관없이 코드에 설명을붙인 것을 말한다.컴파일 과정에서 주석은 무시되고 실행문만  바이트 코드로 번역된다. 따라서 주석을 많이 작성한다고 해서 전체 프로그램의 크기가 커지는 것은 아니므로 가급적이면 설명이 필요한 코드에 주석을 달아 두는 것이 좋다.


명령실행이 안되면 환경변수 추가

: 컴퓨터-속성-고급 시스템 설정-고급 탭에서 환경변수 추가

( ...); C:\Program Files\Java\jdk1.8.0_121\bin


jdk tools 환경변수 추가

시스템 변수 - 새로만들기    

변수이름 : CLASSPATH

변수 값 : .;C:\Program Files\Java\jdk1.8.0_181\lib\tools.jar;


이클립스 설치 (Get Eclipse Neon)

http://www.eclipse.org/downloads/


처음 실행할 때 작업공간(work space) 설정



프로젝트 생성

File -> New -> Java Project


신규 클래스 생성

File -> New -> Class



메인 메소드 작성 (HelloWorld)

1
2
3
4
5
6
7
package jump2java;
 
public class HelloWorld {
    public static void main(String args[]) {
        System.out.println("Hello World");
    }
}
cs

public class 


Run -> Run As -> Java Application로 실행하면 아래 창에 실행결과가 뜬다.

(단축기 Ctrl + F11 이며 Window-Preferences-General-Keys에서 단축키 설정 가능)


이클립스 소스 자동 정렬기능

Ctrl + Shift + F


문자열 출력

1
2
3
4
5
6
7
8
9
package jump2java;
 
public class HelloWorld {
    public static void main(String[] args) {
        String name = "홍길동";
        System.out.println("내 이름은  " + name + "입니다.");
    }
}
 
cs

(" " + 변수명 + " ");



사용자 정의 자료형 정의


Animal 클래스를 먼저 정의

class Animal {
}

Animal 자료형 변수 cat

Animal cat;



자바의 부울 자료형 예제


1
2
3
4
5
6
7
8
9
package jump2java;
 
public class HelloWorld {
    public static void main(String args[]){
        int i=3;
        boolean isOdd = i % 2 == 2;
        System.out.println(isOdd);
    }
}
cs

Output : false



자바에서 문자열을 new 키워드로 객체 생성 가능 (하지만 가독성과 컴파일 최적화를 이유로 권장되지는 않음)


String a = new String("Happy Java");
String b = new String("a");
String c = new String("123");

primitive(원시) 자료형

int, long, double, float, boolean, char 등을 자바에서 primitive 자료형이라하며, new 키워드로 생성 불가 (literal 로만 초기화 가능)


문자열 비교 equals
== 은 두개의 자료형이 동일한 객체인지를 판별할 때 사용하는 연산자이기 때문에 문자열을 비교할 때는 equals를 쓴다.

1
2
3
4
5
6
7
8
9
10
package jump2java;
 
public class HelloWorld {
    public static void main(String args[]){
        String a = "hello";
        String b = new String("hello");
        System.out.println(a.equals(b));
        System.out.println(a==b);
    }
}
cs

Output : 

true

false



문자열의 index를 return하는 indexOf


1
2
3
4
5
6
7
8
9
package jump2java;
 
public class HelloWorld {
    public static void main(String args[]){
        String a = "Hello Java";
        System.out.println(a.indexOf("Java"));
    }
}
 
cs

Output

6



substring 메소드

1
2
3
4
5
6
7
8
9
package jump2java;
 
public class HelloWorld {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("Hello");
        System.out.println(sb.substring(04));
    }
}
cs
Output :
Hell

end index의 문자는 제외되고 출력된다.


배열의 길이를 알 수 있는 length 메소드
1
2
3
4
5
6
7
8
9
10
package jump2java;
 
public class HelloWorld {
    public static void main(String[] args) {
        String[] weeks = {"월""화""수""목""금""토""일"};
        for (int i=0; i<weeks.length; i++) {
            System.out.print(weeks[i]);
        }
    }
}
cs

Output :

월화수목금토일



제네릭스 (Generics)


제네릭스를 사용하지 않은 경우

1
2
3
4
5
6
ArrayList aList = new ArrayList();
aList.add("hello");
aList.add("java");
 
String hello = (String) aList.get(0);
String java = (String) aList.get(1);
cs


다음과 같이 형 변환이 필요

1
2
String hello = (String) aList.get(0); // Object 를 String 으로 캐스팅한다. (String)
 
cs


제네릭스를 사용한 경우

1
2
3
4
5
6
ArrayList<String> aList = new ArrayList<String>();
aList.add("hello");
aList.add("java");
 
String hello = aList.get(0);
String java = aList.get(1);
cs


명시적으로 type을 지정함으로써 잘못된 형 변환을 피할 수 있다.




맵(Map) 자료형

Map은 Key와 Value라는 것을 한 쌍으로 갖는 자료형이다. Associative array, Hash 라고도 불린다.

keyvalue
people사람
baseball야구

리스트나 배열처럼 순차적이 아닌 key를 통해 value를 얻는다.


제네릭스를 이용한 HashMap 생성

1
import java.util.HashMap;
cs
HashMap을 사용하기위한 import


1
2
3
HashMap<StringString> map = new HashMap<StringString>();
map.put("people""사람");
map.put("baseball""야구");
cs

key와 value가 String 형태인 HashMap 생성, 입력은 put메소드를 이용



List 자료형과 contains 메소드 활용한 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package jump2java;
import java.util.ArrayList;
 
public class HelloWorld {
    public static void main(String[] args) {
        ArrayList<String> pocket = new ArrayList<String>();
        pocket.add("paper");
        pocket.add("handphone");
        pocket.add("money");
 
        if (pocket.contains("money")) {
            System.out.println("택시를 타고 가라");
        }else {
            System.out.println("걸어가라");
        }
    }
}
 
cs


boolean 활용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package jump2java;
import java.util.ArrayList;
 
public class HelloWorld {
    public static void main(String[] args) {
        boolean watch = true;    // false 대입하면 걸어가라 
        ArrayList<String> pocket = new ArrayList<String>();
        pocket.add("paper");
        pocket.add("handphone");
 
        if (pocket.contains("money")) {
            System.out.println("택시를 타고 가라");
        }else if(watch) {
            System.out.println("택시를 타고 가셈");
        }else {         
            System.out.println("걸어가라");
        }
    }
}
 
cs

Output : 

택시를 타고 가셈




for each 문

for문과 동일한 키워드이나 조건식이 다르다.

1
2
3
for (type var: iterate) {
    body-of-loop
}
cs

iterate는 루프를 돌릴 객체이며, 한개씩 순차적으로 var에 대입되어 for문을 수행. 

iterate부분에 들어가는 타입은 배열 및 ArrayList 등이 가능.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package jump2java;
import java.util.ArrayList;
 
public class HelloWorld {
    public static void main(String[] args) {
        ArrayList<String> aList = new ArrayList<String>();
        aList.add("abc");
        aList.add("DEF");
        
        String[] numbers = {"one""two""three"};
        for(String number: numbers) {
            System.out.print(number+" ");
        }
        System.out.print("\n");
        for(String hello: aList) {
            System.out.println(hello);
        }
    }
}
 
cs


Output :

one two three 

abc

DEF



'Study > Java' 카테고리의 다른 글

Java Network 프로그래밍 기초  (0) 2017.06.03
NIO 기반 네트워킹  (0) 2017.05.30
JAVA - NIO  (0) 2017.05.29
Java - OOP_인터페이스와 다형성  (0) 2017.03.20
Java - OOP_클래스와 상속, 생성자, 오버로딩/오버라이딩  (0) 2017.03.17
728x90

 

 

// 문자를 입력받고 입력된 문자의 수 출력하기

#include <stdio.h>


void ClearLineFrom_ReadBuffer(void)

{

while (getchar() != '\n');

}


int main(void)

{

int total = 0;

char input;


while (1)

{

fputs("문자 입력 (종료하려면 Ctrl+Z): ", stdout);

input = getchar();

if (input == EOF)

break;


ClearLineFrom_ReadBuffer();

total++;

}


printf("입력된 문자 갯수: %d \n", total);

return 0;

}



// 숫자 n개만큼 입력받고 최대,최소값, 합, 평균 출력하기

#include <stdio.h>


#define data_num 7


int main(void)

{

int iNum;

int cnt=1; // 최초1회 입력받고 이후 loop

int max, min, sum=0;

double avg;

// 최소값과 최대값이 0으로 고정되지 않도록 최초 1회 입력받음

printf("정수 입력 : ");

scanf("%d", &iNum);

max = min = sum = iNum;


// 이후 남은 자료갯수만큼 입력받음

for (cnt; cnt < data_num; cnt++)

{

printf("정수 입력 : ");

scanf("%d", &iNum);

if (iNum > max)

max = iNum;


if (iNum < min)

min = iNum;

sum = sum + iNum;

}


avg = (double)sum / data_num;

printf("최대값 %d, 최소값 %d, 합 %d, 평균 %f \n", max, min, sum, avg);


return 0;

}


// 10진수->n진수 변환 (재귀함수)

#include <stdio.h>

#define digit 2    // 2진수


void conv_bin(num)

{

int bin;

if (num > 0)

{

bin = num % digit;

num = num / digit;

conv_bin(num);

printf("%d", bin);

}

else

return;

}


int main(void)

{

int num;

scanf("%d", &num);

conv_bin(num);


return 0;

}

'Study > C' 카테고리의 다른 글

size_t  (0) 2017.05.29
enum, auto, 구조체  (0) 2017.03.24
c 복습  (0) 2016.11.03
파일의 분할과 헤더파일의 디자인  (0) 2016.08.30
선행처리기와 매크로2  (0) 2016.08.30
728x90

128usart.7z

main.c

SeialTest (3).7z


---------------------------------

SeialTest.7z



#include <avr/io.h>

#include <util/delay.h>


#define  CLR   0x01      //Clear Display 명령

#define  HOME  0x02      //Return Home 명령 

#define  FNC   0x38      //Function Set 명령 0b00111000

                //Data Length = 8bit. 행수 2행, 문자 폰트 5x8


#define CTL PORTL

#define DB PORTD


#define    RXC          7


void uart0_init(void)

{

UCSR0A = 0x00;

  UCSR0B = 0x18; //Enable transmitter

  UCSR0C = 0X06;        // No psrity, 1stop bit, 8bit data


  UBRR0L = 0x67; //set baud rate lo 16Mhz baud rate 9600!!

  UBRR0H = 0x00; //set baud rate hi

}


unsigned char USART_Receive(void)

{

/* Wait for data to be received */

while(!(UCSR0A &(1<<RXC)))

;


/* Get and return received data from buffer */

return UDR0;

}


void LCD_PortSetting(void)

{

  DDRD = 0xFF;        //data bus line

  DDRL = 0xFF;        //control line (0~2 제어핀 사용)

  //D0: RS ,D1: R/W ,D2: EN

}


void IR_Write(unsigned char Data)  

{

  CTL &= 0xFC;    //RS = 0, Write Enable

  _delay_us(1);    //Enable 까지 최소 대기 시간 40ns

  CTL |= 0x04;    //Enable 활성화

  _delay_us(1);    //

  DB = Data;    //Data

  _delay_us(1);

  CTL = 0b00000010;  //Disable, Read Mode  


}


void DR_Write(unsigned char Data)

{

  CTL = 0x01;    //RS = 1, Write Enable

  _delay_us(1);    //Enable 까지 최소 대기 시간 40ns

  CTL |= 0x04;    //Enable 활성화

  _delay_us(1);    //

  DB = Data;    //Data

  _delay_us(1);

  CTL = 0b00000010;  //Disable, Read Mode  

}


void LCD_Char(unsigned char ucChar)

{

  _delay_ms(1); // 명령어 쓰기 전 일정 시간 지연, Busy Flage 확인 대용

  DR_Write(ucChar);  

}


void LCD_Position(unsigned char ucCol, const char ucRow)

{

    IR_Write(0x80 | (ucRow + ucCol * 0x40));

}



void LCD_String(unsigned char ucLine,unsigned char ucRow, const char* ccString)        //    문자열 출력 함수

{                                                    // ucPosition 값에 따라 LCD_Position 값이 달라짐

    LCD_Position(ucLine, ucRow);

    while(*ccString != 0)                            //    *ccString이 null을 가리킬때까지

    {

        LCD_Char(*ccString);

        ccString++;                                    //    문자열의 주소값이 자료형만큼 증가

        if(*ccString <= 0x0F)

        {

            LCD_Position(1,0);

            _delay_ms(2);

        }

    }

}



void LCD_drive()

{

  _delay_ms(50);

  IR_Write(FNC);

  _delay_ms(5);

  IR_Write(FNC);

  _delay_us(100);

  IR_Write(FNC);

  _delay_ms(2);

  IR_Write(0x0E); // DDD RAM내용 표시, 커서 ON, 커서 깜빡임 OFF

  _delay_ms(2);  

  IR_Write(CLR); // Display Clear

  _delay_ms(30);

  IR_Write(0x06); // Entry Mode Set, 커서위치를 오른쪽으로 증가

  _delay_ms(2);

}



void LCD_Usart()

{

int cnt=0;

LCD_Delete();

_delay_ms(2);

LCD_Position(0,0);

while(1)

{

while((UCSR0A&0x80)==0x80)

{

LCD_Char(UDR0);

cnt++;

if(cnt==16)

{

cnt=0;

LCD_Delete();

_delay_ms(2);

}

}

}

}


void LCD_Delete(void)

{

    _delay_ms(1);

    IR_Write(0x01);

}


int main(void)

{

uart0_init();

  LCD_PortSetting();

  LCD_drive();    

  _delay_ms(2);


  DDRB = 0xFF;

PORTB = 0x00;


while(1)

{

LCD_Usart();

}

  return 0;

}



---------------------------------------------------------------------------

















#include <avr/io.h>


/////////// USART0 ///////////////////////////////////////////////

#define UDR0 (*((volatile unsigned char*)0xC6))


#define UCSR0A (*((volatile unsigned char*)0xC0))

#define UCSR0B (*((volatile unsigned char*)0xC1))

#define UCSR0C (*((volatile unsigned char*)0xC2))


#define UBRR0L (*((volatile unsigned char*)0xC4))

#define UBRR0H (*((volatile unsigned char*)0xC5))


#define    TXEN         3

#define    RXEN         4

#define    USBS        3

#define    UCSZ0        1

#define    UDRE        5

#define    RXC          7



#define FOSC 16000000 // Clock Speed

#define BAUD 9600 // Serial 

#define MYUBRR FOSC/16l/BAUD-1


void USART_Init(unsigned int ubrr);

void USART_Transmit(unsigned char data);

unsigned char USART_Receive(void);


int main(void)

{

int i;

USART_Init(MYUBRR);

USART_Transmit("T");

DDRB = 0xFF;

PORTB = 0x00;


while(1)

{

switch(USART_Receive())

{

case '1' : 

PORTB = 0xFF;

break;

case '2' :

PORTB = 0x00;

break;

case '3' :

PORTA = 0xFB;

break;

}

}

return 0;

}


void USART_Init(unsigned int ubrr)

{

/* Set baud rate */

UBRR0H = (unsigned char) (ubrr>>8);

UBRR0L = (unsigned char) ubrr;

/* Enable receiver and transmitter */

UCSR0B = (1<<RXEN) | (1<<TXEN);

/* Set frame format : 8data, 1stop bit */

UCSR0C = 3<<UCSZ0;

}


void USART_Transmit(unsigned char data)

{

/* Wait for empty transmit buffer */

while(! (UCSR0A & (1<<UDRE)))

;

UDR0 = data;

}


unsigned char USART_Receive(void)

{

/* Wait for data to be received */

while(!(UCSR0A &(1<<RXC)))

;


/* Get and return received data from buffer */

return UDR0;

}



'Study > Embedded' 카테고리의 다른 글

아두이노 LCD  (0) 2017.06.01
아두이노 기초  (0) 2017.05.25
7/21 Atmega128 포트/ win32 api  (0) 2016.07.21
7/8 LCD제어2  (0) 2016.07.08
7/5 LCD 제어  (0) 2016.07.05
728x90

EditMode에서 실시간 반영


[ExecuteInEditMode] 키워드를 스크립트에서 class위에 추가


1
2
3
[ExecuteInEditMode]
public class UIRoot : MonoBehaviour
{ ... }
cs


'Study > Unity Engine' 카테고리의 다른 글

유니티3d 로드쇼 후기  (0) 2016.10.21
728x90

vs2015-wpf

Save the Humans.7z



wpf-user guide

WPF_user_guide.7z.001

WPF_user_guide.7z.002



wpf 연습(if~else문 활용)

우상단 체크박스에 체크하지 않으면 Text block에 위와 같은 문구가 뜬다.

체크 후에 버튼을 눌러보면 처음엔 오른쪽-다시 한번 눌렀을 땐 왼쪽으로 정렬이 된다. 


처음 실행시 text에 right가 아니기 때문에 else문이 실행되고 text속성이 right로 변경, HorizontalAlignment 속성도 right로 변경된다.

다시 한번 눌렀을 때는 if문이 만족되어 각각 left로 변경됨을 볼 수 있다.


아래는 그리드에 대한 재멀(xaml) 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<Window x:Class="Practice_Using_IfElse.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Practice_Using_IfElse"
        mc:Ignorable="d"
        Title="MainWindow" Height="192" Width="525">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button x:Name="changeText" Content="Change the lable if checked" 
        HorizontalAlignment="Center" VerticalAlignment="Center" Click="changeText_Click"/>
 
        <CheckBox x:Name="enableCheckbox" Content="Enable lable changing" Grid.Column="1" 
        HorizontalAlignment="Center" VerticalAlignment="Center"/>
 
        <TextBlock x:Name="labelToChange" Grid.Row="1" TextWrapping="Wrap" Text="Press the button to change my text" 
        Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>
cs


xaml.cs 코드의 일부분 (이벤트 핸들러 메서드에 대한 C# 코드)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 private void changeText_Click(object sender, RoutedEventArgs e)
        {
            if (enableCheckbox.IsChecked == true)
            {
                if(labelToChange.Text == "Right")
                {
                    labelToChange.Text = "Left";
                    labelToChange.HorizontalAlignment = HorizontalAlignment.Left;
                }
                else
                {
                    labelToChange.Text = "Right";
                    labelToChange.HorizontalAlignment = HorizontalAlignment.Right;
                }
            }
            else
            {
                labelToChange.Text = "Text changing is disabled";
                labelToChange.HorizontalAlignment = HorizontalAlignment.Center;
            }
        }
cs


'Study > C#' 카테고리의 다른 글

C# 클래스, 메소드  (0) 2017.04.04
c# 복습  (0) 2017.03.31
5/27 업무일지 c#학생성적관리(콘솔)  (0) 2016.05.27
c# 클래스 복습2  (0) 2016.05.23
c# 스터디일지 -클래스  (0) 2016.05.22
728x90
공용체 union 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
 
union smart
{
    int A;    short B;
    int C;    char D;
}obj;
 
int main()
{    
    obj.A = 0x12345678;    obj.B = 0x12345678;
    obj.C = 0x12345678;    obj.D = 0x12345678;
        
    printf("Size of Smart: %d\n"sizeof(union smart));
    printf("%x\n", obj.A);    printf("%x\n", obj.B);
    printf("%x\n", obj.C);    printf("%x\n", obj.D);
    return 0;
}
cs


위 공용체의 size는 4byte


Little Endian

78 

 56

 34

 12


obj.A=12345678   // int A

obj.B=5678        // short B

obj.C=12345678  // int C

obj.D=78           // char D



함수 포인터


: 함수를 가리키는 포인터 


int SoSimple(int num1, int num2) { ....}


위 함수에 대한 함수 포인터 변수 선언

int (*fptr) (int, int);



함수 포인터 변수에 SoSimple 주소값 저장

fptr = SoSimple



이는 fptr(3, 4);    // SoSimple(3, 4)와 동일한 결과


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
void Add(int n1, int n2)
{
    printf("%d + %d = %d \n", n1, n2, n1 + n2);
}
 
int main()
{    
    int num1 = 10, num2 = 20;
 
    void(*fptr)(intint= Add;
    fptr(num1, num2);
    return 0;
}
cs

Output :

10 + 20 = 30



void형 포인터 변수는 어떠한 변수의 주소 값이든 담을 수 있지만(함수의 주소값도)

값의 변경이나 참조를 비롯한 어떤 포인터 연산도 불가

: type 정보가 없기 때문에 당연


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
void voidFunc(void)
{
    printf("void ptr test\n");
}
 
int main()
{
    void(*fptr)(void= voidFunc;
    fptr();
    return 0;
}
cs

Output :

void ptr test


함수 포인터 사용 이유 (참고 : http://norux.me/8)  


①프로그램 코드의 간결

②중복 코드를 줄이기 위해서

③상황에 따라 해당되는 함수를 호출할 수 있음


그외에 참고 https://kldp.org/node/133026




가변 인자 함수


num = Sum(3, 1, 2, 3);    // 3은 이후에 전달되는 인자의 갯수 (1,2,3)


1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
 
int Sum(int n, ...)    // 가변 인자에 대한 선언
{
    printf("n=%d \n", n);    
    return 0;
}
 
int main()
{    
    Sum(3123);
    return 0;
}
cs

Output :

n=3


가변 인자 함수의 호출을 통해 전달되는 인자 정보 추출


#include <stdarg.h>

1. 가변인자를 가리킬 수 있는 참조자 선언     : va_list

2. 참조자가 가변인자를 실제 참조                : va_start

3. 참조자를 통해 전달된 정보 추출               : va_arg

4. 참조자가 가변인자를 가리키지 않도록 해제 : va_end


Output :

3+5=2=10



22행 : (vlist, int) 첫번째 인자는 참조자 이름, 두번째 인자는 참조대상의 type



'Study > C' 카테고리의 다른 글

enum, auto, 구조체  (0) 2017.03.24
C 복습-콘솔 입출력  (0) 2017.02.11
파일의 분할과 헤더파일의 디자인  (0) 2016.08.30
선행처리기와 매크로2  (0) 2016.08.30
선행처리기와 매크로  (0) 2016.08.29
728x90

유니티 로드쇼에서는 vr과 영화, 광고를 통한 수익, 모바일 지원환경 등 많은 것을 듣고 보고 온 시간이었습니다.

아직 유니티는 막 배우는 단계이지만 이를 잘 활용해서 좋은 창작물을 만들 수 있었으면 좋겠습니다.


강연도 집중해서 잘 들었고 강의 중간중간 질문하시는 분들의 열기도 뜨거웠습니다. 

날카로운 질문을 던지는 분들 외에도 중1 개발자분도 기억에 남네요~


유니티가 가지고 있는 장점들을 앞으로도 더 발전시키고 부족한 점들을 개선시키면 좋겠습니다.
특히 엔진 메뉴얼과 멀티스레딩 지원 부분을 강화할 필요가 있어 보입니다.




@ Unity 3D VR

1 unit = 1 meter

camera - vr both 를 통해 쉽게 설정 가능 


sdk - oculus, gear vr... etc...지원


vr - ui and ux 지원

3d ui- reference들 참고하면 좋다.  


Motion sicknesss

-over stimulation theory 

-sensory conflict theory


@ 고려할 사항

과하지 않은 움직임(초당 7도), 카메라 회전 고정 금지, 과한 가속 운동 금지


@ 수렴초점 불일치

망막 경합(retinal rivalry)

양안 경합(binocular ri-)


Convergence Insufficiency

(ex- 카메라가 object를 너무 가까이 둘 때 양눈이 보는 이미지가 갈라짐, fps에서 조준시점)

Fps hand scaling- 총이 실제로 작아짐을 확연히 느끼게 됨. 벽에 파묻히는 문제는 벽에 가까이 다가섬을 지양하도록


성인 기준으로 vr이 만들어져있고 여러 문제 등으로 13세이하에는 권장되지 않음



@ Multi threaded Rendering 개선 및 강화중

5.4 버전이 ms 레이턴시를 많이 줄였고 지속적으로 개선중이다.



@ vr환경에서 개발가능한 편집기 개발중

carte blanche를 개발하는중. (유니티 내부 유니티 랩스에서 개발중)  



unity 3d 관련 forums- unity hub, facebook unity korea 



'Study > Unity Engine' 카테고리의 다른 글

스크립트의 실시간 반영 - ExecuteInEditMode  (0) 2016.12.08
728x90

객체 포인터의 참조 관계


근로학생은 학생이자 사람이다.

따라서 상속관계는 다음과 같다.


class Student : public Person

{  };


class PartTimeStudent : public Student

{  };


따라서 아래와 같이 포인터 변수를 통해 참조가 가능하다.


Person * ptr = new Student();

Person * ptr = new PartTimeStudent();

Student * ptr = new PartTimeStudent();


다음과 같은 참조는 불가능하다. 모든 학생이 근로학생이란건 논리적으로도 맞지 않다.

PartTimeStudent * ptr = new Student();




Person * ptr;

따라서, 위와 같은 포인터 변수는, Person 클래스의 객체 또는 Person을 직간접적으로 상속하는 모든 클래스의 객체를 가리킬 수 있다. (객체 주소 값 저장 가능)



'Study > C++' 카테고리의 다른 글

상속의 이해  (0) 2016.10.13
상속  (0) 2016.09.30
const, friend, static, mutable 선언  (0) 2016.09.29
복사 생성자, 얕은 복사와 깊은 복사, 임시 객체  (0) 2016.09.28
객체 배열과 this포인터  (0) 2016.09.27
728x90

유도 클래스의 객체 생성 과정


유도 클래스의 객체 과정에서 기초 클래스의 생성자는 100% 호출된다.


유도클래스의 생성자에서 기초 클래스의 생성자 호출을 명시하지 않으면, 기초 클래스의 void 생성자가 호출된다.

(기초 클래스의 void생성자가 정의되있어야 함)



#include <iostream>
using namespace std;

class SoBase
{
private:
	int baseNum;
public:
	SoBase() : baseNum(20)
	{
		cout << "SoBase()" << endl;
	}
	SoBase(int n) : baseNum(n)
	{
		cout << "SoBase(int n)" << endl;
	}
	void ShowBaseData()
	{
		cout << baseNum << endl;
	}
};

class SoDerived : public SoBase	// public 상속
{
private:
	int derivNum;
public:
	SoDerived() : derivNum(30)	
	{ 
		// 생성자, 기초 클래스의 생성자 호출을 명시하지 않음
		cout << "SoDerived()" << endl;
	}
	SoDerived(int n) : derivNum(n)	
		// 역시 기초 클래스 생성자 호출 명시하지 않음
	{
		cout << "SoDerived(int n)" << endl;
	}
	SoDerived(int n1, int n2) : SoBase(n1), derivNum(n2) 
		// n1을 인자로 받는 기초 클래스 생성자 호출 명시
	{
		cout << "SoDerived(int n1, int n2)" << endl;
	}
	void ShowDerivData()
	{
		ShowBaseData();
		cout << derivNum << endl;
	}
};

int main(void)
{
	cout << "case1..... " << endl;
	SoDerived dr1;
	dr1.ShowDerivData();
	cout << "-------------------" << endl;
	cout << "case2..... " << endl;
	SoDerived dr2(12);
	dr2.ShowDerivData();
	cout << "-------------------" << endl;
	cout << "case3..... " << endl;
	SoDerived dr3(23, 24);
	dr3.ShowDerivData();
	return 0;
};


Output : 

case1.....

SoBase()

SoDerived()

20

30

-------------------

case2.....

SoBase()

SoDerived(int n)

20

12

-------------------

case3.....

SoBase(int n)

SoDerived(int n1, int n2)

23

24



출력결과를 보면 유도 클래스의 객체를 생성할 때 기초 클래스의 생성자가 먼저 호출됨을 알 수 있다.



case 3의 객체 생성 과정은 다음과 같다.


유도 클래스의 객체를 생성할 때 생성자를 호출하고 이니셜라이저에 의해 n1, n2 인자가 전달되면서 유도 클래스의 생성자가 호출된다.

이 때 생성자가 호출되었다고 해서 바로 실행이 되는 것이 아니다.

기초 클래스의 생성자 호출이 우선되어야 한다.  


이니셜라이저의 SoBase(n1)에 의해 매개 변수 n1으로 전달된 값을 인자로 전달받을 수 있는 기초 클래스의 생성자를 호출한다. 호출이 완료되면, 

기초 클래스의 멤버 변수가 초기화되고 이어 유도 클래스의 생성자 실행이 완료되면서 유도 클래스 멤버 변수도 초기화가 이루어진다.



이렇게 객체가 생성되며, 앞서 이야기했듯이 이니셜라이저에서 기초 클래스 생성자 호출이 명시되지 않으면 void 생성자를 호출한다.


유도 클래스에서도 다음의 원칙은 적용된다.

"클래스의 멤버는 해당 클래스의 생성자를 통해 초기화해야한다."




유도 클래스 객체의 소멸 과정


소멸자는 명시적 선언이 필요없다. 다음 예제를 통해, 유도 클래스의 객체가 소멸될 때, 어느 시점에 소멸자가 호출되고 실행되는지 알 수 있다.


#include <iostream>
using namespace std;

class SoBase
{
private:
	int baseNum;
public:
	SoBase(int n) : baseNum(n)
	{
		cout << "SoBase() : " << baseNum << endl;
	}
	~SoBase()
	{
		cout << "~SoBase() : " << baseNum << endl;
	}
};

class SoDerived : public SoBase
{
private:
	int derivNum;
public:
	SoDerived(int n) : SoBase(n), derivNum(n)
	{
		cout << "SoDerived() : " << derivNum << endl;
	}
	~SoDerived()
	{
		cout << "~SoDerived() : " << derivNum << endl;
	}
};

int main(void)
{
	SoDerived drv1(15);
	SoDerived drv2(27);
	return 0;
};


Output :

SoBase() : 15

SoDerived() : 15

SoBase() : 27

SoDerived() : 27

~SoDerived() : 27

~SoBase() : 27

~SoDerived() : 15

~SoBase() : 15


출력결과를 보면 유도 클래스의 객체가 소멸될 때, 유도 클래스의 소멸자가 실행되고 기초 클래스의 소멸자가 실행된다. 

(즉 객체에 소멸순서는 생성순서와 반대)



유도 클래스의 생성자 및 소멸자 정의 모델

생성자에서 동적 할당한 메모리 공간은 소멸자에서 해제한다. 상속과 연관된 클래스의 소멸자도 이러한 원칙을 지켜 정의해야 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Person
{
private:
    char * name;
public:
    Person(char * myname)
    {
        name=new char[strlen(myname)+1];
        strcpy(name, myname);
    }
    ~Person()
    {
        delete []name;
    }
    void WhatYourName() const
    {
        cout<<"My name is "<<name<<endl;
    }
};
 
class UnivStudent : public Person
{
private:
    char * major;
public:
    UnivStudent(char * myname, char * mymajor)
        :Person(myname)
    {
        major=new char[strlen(mymajor)+1];
        strcpy(major, mymajor);
    }
    ~UnivStudent()
    {
        delete []major;
    }
    void WhoAreYou() const
    {
        WhatYourName();
        cout<<"My major is "<<major<<endl<<endl;
    }
};
cs


상속과 생성자의 호출 예제


https://goo.gl/4Ibgjm



생성자와 소멸자 정의 예제

#include <iostream>
using namespace std;

class MyFriendInfo
{
private:
	char * name;
	int age;
public:
	MyFriendInfo(char * fname, int fage) : age(fage)
	{
		name = new char[strlen(fname) + 1];
		strcpy(name, fname);
	}
	void ShowMyFriendInfo()
	{
		cout << "이름: " << name << endl;
		cout << "나이: " << age << endl;
	}
	~MyFriendInfo()
	{
		delete[]name;
	}
};

class MyFriendDetailInfo : public MyFriendInfo
{
private:
	char * addr;
	char * phone;
public:
	MyFriendDetailInfo(char *fname, int fage, char *faddr, char *fphone)
		:MyFriendInfo(fname, fage)
	{
		addr = new char[strlen(faddr) + 1];
		phone = new char[strlen(fphone) + 1];
		strcpy(addr, faddr);
		strcpy(phone, fphone);
	}
	void ShowMyFriendDetailInfo()
	{
		ShowMyFriendInfo();
		cout << "주소: " << addr << endl;
		cout << "전화: " << phone << endl << endl;
	}
	~MyFriendDetailInfo()
	{
		delete[]addr;
		delete[]phone;
	}
};

int main(void)
{
	MyFriendDetailInfo myfren("철수", 23, "서울종로구 사직동", "010-0000-0000");
	myfren.ShowMyFriendDetailInfo();
	return 0;
};

Output:
이름: 철수
나이: 23
주소: 서울종로구 사직동
전화: 010-0000-0000


protected로 선언된 멤버가 허용하는 접근 범위

세 가지 형태의 상속
private < protected < public



상속을 할 경우, 유도클래스에서는 private와 달리 protected로 선언된 멤버 변수에는 접근 가능

private멤버는 클래스내에서만 접근 가능하다.

주의할 것은 어떠한 형태로 상속하던지, 유도 클래스에서 상속한 private멤버는 접근이 불가능하단 것이다.


실제로는 C++에서 public 이외의 상속은 다중 상속과 같이 특별한 경우가 아니면 잘 사용하지 않는다.




상속의 기본 조건


is a 관계의 성립


전화 -> 무선 전화기            

컴퓨터 -> 노트북 컴퓨터    (Notebook Computer is a Computer)


컴퓨터를 두고 이동성이 있다는 이야기를 하진 않는다.

노트북 컴퓨터는 컴퓨터의 특성에 이동성이라는 특성이 추가된 것이다.


전화기가 더욱 넓은 범주지만 기능은 무선 전화가 더욱 많다고 이해하면 된다.

따라서 전화기가 기초 클래스가 되고, 무선전화기가 유도 클래스가 된다.



has a 관계의 성립


경찰은 총을 소유한다. (has a)


기초 클래스가 Gun, 유도 클래스가 Police


이 경우 의존도(커플링)가 높다.

Police와 Gun이 강한 연관성을 띠게되어, 총을 소유하지 않은 경찰이나 다른 무기를 소유하는 경찰을 표현하기가 쉽지 않아진다.


따라서 이런 has a관계의 상속은 좋지못하며, has a 관계는 포함으로 표현한다. 

따라서 아래와 같이 gun을 police의 멤버로 선언하는 것이 일반적이고 단순하며, 확장성 높은 방법이다.


위와 같은 클래스 정의는 권총을 소유하지 않거나(NULL), 다른 무기를 가진 경찰을 표현하기 쉬워진다.


커플링이 높은 클래스는 유연성이 낮기 때문에 주의해야한다.



+ Recent posts