Javaによるオブジェクト指向プログラミング

Javaのクラスは参照型(reference type)です。

注)Javaのローカル変数は、明示的に初期化しなければなりません。
注)Javaのメンバー変数は、明示的に初期化しなくても暗黙的にデフォルト値(default value)で初期化されます。


 

robot.java

class Robot {
  private double x, y;

  Robot() {
    set(0, 0);
  }

  Robot(double x, double y) {
    set(x, y);
  }

  void set(double x, double y) {
    this.x = x;
    this.y = y;
  }

  double getX() {
    return x;
  }

  double getY() {
    return y;
  }

  void move(double dx, double dy) {
    x += dx;
    y += dy;
  }

  void print() {
    System.out.println("x = " + x);
    System.out.println("y = " + y);
  }
}
 

 

main.java

class Main {
  public static void main(String... args) {
    Robot robot1 = new Robot();
    robot1.move(1, 1);
    robot1.print();
    System.out.println("x = " + robot1.getX());
    System.out.println("y = " + robot1.getY());

    Robot[] robot2 = new Robot[]{new Robot(), new Robot()};
    for (Robot robot : robot2) {
      robot.move(1, 1);
      robot.print();
    }

    int n = 10;
    Robot[] robot3 = new Robot[n];
    for (int i = 0; i < robot3.length; i++) {
      robot3[i] = new Robot(0, 0);
      robot3[i].move(i, i);
      robot3[i].print();
    }
  }
}
 

 

コンパイル

javac0.bat(ファイル名をjavac.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
javac *.java
 

 

実行

java0.bat(ファイル名をjava.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
java Main
pause
 

継承

 

inheritance.java

class Position {
  double x, y;

  Position() {
    set(0, 0);
  }

  Position(double x, double y) {
    set(x, y);
  }

  void set(double x, double y) {
    this.x = x;
    this.y = y;
  }
}

class Robot extends Position {
  Robot() {
    super();
  }

  Robot(double x, double y) {
    super(x, y);
  }
}

class Main {
  public static void main(String... args) {
    Robot robot0 = new Robot();
    System.out.println("x = " + robot0.x);
    System.out.println("y = " + robot0.y);

    Robot robot1 = new Robot(1, 1);
    System.out.println("x = " + robot1.x);
    System.out.println("y = " + robot1.y);
  }
}
 

packageの作成とimport

 

packageの作成

D:\pkg\pkg1\pkg2\pkg3\Hello.java

package pkg1.pkg2.pkg3;

public class Hello {
  public Hello() {
    System.out.println("Hello!");
  }
}
 

 

packageのコンパイル

D:\pkg\javac0.bat(ファイル名をjavac.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
javac D:/pkg/pkg1/pkg2/pkg3/*.java
 

 

JARライブラリの作成

D:\pkg\jar0.bat(ファイル名をjar.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
jar cfv lib.jar pkg1
 

注)jar cfv lib.jar D:/pkg/pkg1 とするとうまくいきません!


Mainクラスの作成(packageのインポート)

D:\src\main.java

import pkg1.pkg2.pkg3.Hello;

class Main {
  public static void main(String... args) {
    new Hello();
    //new pkg1.pkg2.pkg3.Hello();
  }
}
 

 

Mainクラスのコンパイル

D:\src\javac0.bat(ファイル名をjavac.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
javac -cp D:/pkg *.java
 

 

Mainクラスの実行

D:\src\java0.bat(ファイル名をjava.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
java -cp .;D:/pkg Main
pause
 

 

Mainクラスのコンパイル(JARライブラリを使った場合)

D:\src\javac0j.bat(ファイル名をjavac.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
javac -cp D:/pkg/lib.jar *.java
 

 

Mainクラスの実行(JARライブラリを使った場合)

D:\src\java0j.bat(ファイル名をjava.batにすると暴走します)

set JAVA_HOME=D:\sdk\jdk
set path=%path%;%JAVA_HOME%\bin
java -cp .;D:/pkg/lib.jar Main
pause
 

Accessibility
 access modifier   same class   same package   subclasses in other package   from anywhere 
public
protected ×
no modifier × ×
private × × ×

参考サイト

 

C++によるオブジェクト指向プログラミング

コンストラクタはオブジェクトの記憶領域が確保された直後に実行され、ディストラクタはオブジェクトの記憶領域が解放された直後に実行されます。どちらも自動的に実行されます。また、コンストラクタの中で変数を new した場合は、通常ディストラクタの中でその変数を delete します。

注)C++では構造体もクラスも値型(value type)です。
注)A a; クラスAのデフォルトコンストラクタが定義されていれば、aはデフォルトコンストラクタで初期化されます。
注)デフォルト引数(default parameter)のデフォルト値(default value)は、関数のプロトタイプ宣言で設定します。
注)デフォルトコンストラクタとは、引数がないか、全ての引数にデフォルト値が設定されているコンストラクタです。
注)引数無しのコンストラクタと全ての引数がデフォルト引数であるコンストラクタを同時に定義するとエラーになります。
注)static const の整数型メンバー変数を除いて、メンバー変数を宣言と同時に初期化しないこと! → 初期化してもよい!


オブジェクトの初期化と代入

注)C++では初期化の=と代入の=の違いに注意する必要があります。

 

class.cpp

#include <iostream>

class Robot {
public:
  double x = 1, y = 1;
};

int main() {
  Robot robot;
  std::cout << robot.x << std::endl;
  std::cout << robot.y << std::endl;
}
 

 

object.cpp

#include <iostream>

class Robot {
  double x, y;
public:
  Robot();
  Robot(double, double);
  void set(double, double);
  double getX() const;
  double getY() const;
};

//メンバー初期化リストを使った引数無しコンストラクタ&デフォルトコンストラクタ
//Robot::Robot() : x(0), y(0) {}

//引数無しコンストラクタ&デフォルトコンストラクタ
Robot::Robot() {
  set(0, 0);
}

//メンバー初期化リストを使った引数付きコンストラクタ
//Robot::Robot(double x, double y) : x(x), y(y) {}

//引数付きコンストラクタ
Robot::Robot(double x, double y) {
  set(x, y);
}

void Robot::set(double x, double y) {
  this->x = x;
  this->y = y;
}

double Robot::getX() const {
  return x;
}

double Robot::getY() const {
  return y;
}

int main() {
  //デフォルトコンストラクタによる初期化
  Robot robot;
  std::cout << robot.getX() << std::endl;
  std::cout << robot.getY() << std::endl;

  //一時オブジェクトの代入
  robot = Robot();
  robot = Robot(0, 0);

  //デフォルトコピーコンストラクタによる初期化
  Robot robot0(robot);

  //デフォルト代入演算子によるオブジェクトの代入
  robot0 = robot;

  //引数無しコンストラクタによる初期化
  Robot robot1(); // -> NG
  auto robot2 = Robot();

  //引数付きコンストラクタによる初期化
  Robot robot3(3, 3);
  auto robot4 = Robot(4, 4);
}
 

 

robot.hpp

#pragma once

#include <iostream>

class Robot {
  double x, y;

public:
  static int nRobots;

  //default constructor with default parameters
  Robot(double x = 0, double y = 0) : x(x), y(y) {}

  Robot(const Robot& robot) {
    x = robot.x;
    y = robot.y;
  }

  Robot& operator=(const Robot& robot) {
    x = robot.x;
    y = robot.y;
    return *this;
  }

  virtual ~Robot() {}

  void set(double x, double y) {
    this->x = x;
    this->y = y;
  }

  double getX() const {
    return x;
  }

  double getY() const {
    return y;
  }

  void move(double dx, double dy) {
    x += dx;
    y += dy;
  }

  void print() const {
    using namespace std;
    cout << "(x, y) = " << "(" << x << ", " << y << ")" << endl;
  }
};

int Robot::nRobots = 0;
 

 

main.cpp

#include "robot.hpp"

int main() {
  //Robot robot0;
  //Robot robot0(1);
  //Robot robot0(1, 1);
  auto robot0 = Robot();
  robot0.print();

  Robot robot1(robot0);
  robot1 = robot0;
  robot1.move(1, 1);
  robot1.print();

  auto robot2 = new Robot;
  robot2->move(2, 2);
  robot2->print();
  delete robot2;

  //g++ OK, clang++ NG
  Robot::nRobots = 10;
  Robot robot3[Robot::nRobots];
  for (int i = 0; i < Robot::nRobots; i++) {
    robot3[i].set(0, 0);
    robot3[i].move(3, 3);
    robot3[i].print();
  }

  Robot::nRobots = 10;
  auto robot4 = new Robot[Robot::nRobots];
  for (int i = 0; i < Robot::nRobots; i++) {
    robot4[i].set(0, 0);
    robot4[i].move(4, 4);
    robot4[i].print();
  }
  delete[] robot4;
}
 

 

build.bat

set path=d:\sdk\msys64\mingw64\bin;%path%;
g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static *.cpp -o main.exe
strip main.exe

 

robot.hpp

#pragma once

class Robot {
  double x, y;
public:
  static int nRobots;
  Robot(double x = 0, double y = 0);
  Robot(const Robot&);
  Robot& operator=(const Robot&);
  virtual ~Robot();
  void set(double, double);
  double getX() const;
  double getY() const;
  void move(double, double);
  void print() const;
};
 

 

robot.cpp

#include "robot.hpp"
#include <iostream>

int Robot::nRobots = 0;

/* member initialization list
Robot::Robot() : x(0), y(0) {}
Robot::Robot(double x, double y) : x(x), y(y) {}
*/

Robot::Robot(double x, double y) {
  this->x = x;
  this->y = y;
}

//copy constructor
Robot::Robot(const Robot& robot) {
  x = robot.x;
  y = robot.y;
}

//assignment operator overloading
Robot& Robot::operator=(const Robot& robot) {
  x = robot.x;
  y = robot.y;
  return *this;
}

Robot::~Robot() {}

void Robot::set(double x, double y) {
  this->x = x;
  this->y = y;
}

double Robot::getX() const {
  return x;
}

double Robot::getY() const {
  return y;
}

void Robot::move(double dx, double dy) {
  x += dx;
  y += dy;
}

void Robot::print() const {
  using namespace std;
  cout << "(x, y) = " << "(" << x << ", " << y << ")" << endl;
}
 

 

main.cpp

#include "robot.hpp"

int main() {
  //Robot robot0;
  //Robot robot0(1);
  //Robot robot0(1, 1);
  auto robot0 = Robot();
  robot0.print();

  Robot robot1(robot0);
  robot1 = robot0;
  robot1.move(1, 1);
  robot1.print();

  auto robot2 = new Robot;
  robot2->move(2, 2);
  robot2->print();
  delete robot2;

  //g++ OK, clang++ OK
  const int n = 10;
  Robot robot3[n];
  for (int i = 0; i < n; i++) {
    robot3[i].set(0, 0);
    robot3[i].move(3, 3);
    robot3[i].print();
  }

  Robot::nRobots = 10;
  auto robot4 = new Robot[Robot::nRobots];
  for (int i = 0; i < Robot::nRobots; i++) {
    robot4[i].set(0, 0);
    robot4[i].move(4, 4);
    robot4[i].print();
  }
  delete[] robot4;
}
 

 

build.bat

set path=d:\sdk\msys64\mingw64\bin;%path%;
g++ -std=c++17 -O3 -pedantic-errors -s -Wall -c robot.cpp -o robot.o
g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static robot.o main.cpp -o main.exe
strip main.exe

オブジェクトをメンバーに持つクラス

 

member_object.cpp

#include <iostream>

class X {
public:
  double x;
  X(double x = 0);
};

X::X(double x) : x(x) {}

class Y {
public:
  double y;
  Y(double y = 0);
};

Y::Y(double y) : y(y) {}

class Robot {
public:
  X x;
  Y y;
  //引数付きコンストラクタ&デフォルトコンストラクタ
  Robot(double x = 1, double y = 1);
};

//引数付きコンストラクタを使ったメンバー初期化リスト
Robot::Robot(double x, double y) : x(x), y(y) {}
/*
Robot::Robot(double x, double y) {
  this->x = X(x);
  this->y = Y(y);
}
*/

int main() {
  X x;
  Y y;
  std::cout << x.x << std::endl;
  std::cout << y.y << std::endl;
  //Robot robot; // -> OK
  //Robot robot(); // -> NG
  //Robot robot(1, 1); // -> OK
  //auto robot = Robot(); // -> NG
  auto robot = Robot(1, 1);
  std::cout << robot.x.x << std::endl;
  std::cout << robot.y.y << std::endl;
}
 

クラスの継承

 

inheritance.cpp

#include <iostream>

class X {
public:
  double x;
  X(double x = 0);
};

X::X(double x) : x(x) {}

class Y {
public:
  double y;
  Y(double y = 0);
};

Y::Y(double y) : y(y) {}

class Robot : public X, public Y {
public:
  //引数付きコンストラクタ&デフォルトコンストラクタ
  Robot(double x = 1, double y = 1);
};

//スーパークラスの引数付きコンストラクタを使ったメンバー初期化リスト
Robot::Robot(double x, double y) : X(x), Y(y) {}
/*
Robot::Robot(double x, double y) {
  X::x = x;
  Y::y = y;
}
*/

int main() {
  X x;
  Y y;
  std::cout << x.x << std::endl;
  std::cout << y.y << std::endl;
  //Robot robot; // -> OK
  //Robot robot(); // -> NG
  //Robot robot(1, 1); // -> OK
  //auto robot = Robot(); // -> NG
  auto robot = Robot(1, 1);
  std::cout << robot.x << std::endl;
  std::cout << robot.y << std::endl;
}
 

 

array.hpp

#pragma once

class Array {
public:
  static double common;
  static const long length = 10;
private:
  double element[length];
public:
  ArragetY();
  double& operator[](long);
};
 

 

array.cpp

#include "array.hpp"
#include <cassert>

double Array::common = 0;

Array::ArragetY() {
  if (length > 0) {
    for (long i = 0; i < length; i++) {
      element[i] = 0;
    }
  }
}

auto Array::operator[](long index) -> double& {
  assert(0 <= index && index < length);
  return element[index];
}
 

 

main.cpp(オブジェクトを static data area に割り当てるプログラム)

#include "array.hpp"
#include <iostream>

auto array = ArragetY();
//auto array = new ArragetY(); // -> NG

auto main() -> int {
  for (long i = 0; i < Array::length; i++) {
    array[i] = i;
    std::cout << array[i] << std::endl;
  }
  std::cout << Array::common << std::endl;
}
 

 

main.cpp(オブジェクトを stack area に割り当てるプログラム)

#include "array.hpp"
#include <iostream>

auto main() -> int {
  auto array = ArragetY();
  for (long i = 0; i < Array::length; i++) {
    array[i] = i;
    std::cout << array[i] << std::endl;
  }
  std::cout << Array::common << std::endl;
}
 

 

main.cpp(オブジェクトを heap area に割り当てるプログラム)

#include "array.hpp"
#include <iostream>

auto main() -> int {
  auto array = new ArragetY();
  for (long i = 0; i < Array::length; i++) {
    (*array)[i] = i;
    std::cout << (*array)[i] << std::endl;
  }
  delete array;
  std::cout << Array::common << std::endl;
}
 

 

build.bat

set path=d:\sdk\msys64\mingw64\bin;%path%;
clang++ -std=c++17 -O3 -pedantic-errors -s -Wall -static *.cpp -o main.exe
strip main.exe

 

注)Windowsのstack領域のサイズは、2MB。


参考サイト

 

C++におけるオブジェクト

C++ では、クラス(class)を具象化したものがオブジェクト(object)です。例えて言うなら、クラスは鋳型でオブジェクトは鋳型から作られる鋳物です。C++ のオブジェクトは Javaインスタンス(instance)に相当します。
下記の例では、Robot がクラス、robot、robot0、*robot1、robot00、*robot11 がオブジェクトです。

robot.hpp


#pragma once

class Robot {
  double x, y;
public:
  static const int robots;
  Robot(double x = 0, double y = 0);
  ~Robot();
  auto set(double, double) -> void;
  auto getX() const -> double;
  auto getY() const -> double;
  auto move(double, double) -> void;
  auto show() const -> void;
};
 

 

robot.cpp


#include <cstdio>
#include "robot.hpp"

const int Robot::robots = 10;

Robot::Robot(double x, double y) : x{x}, y{y} {}

Robot::~Robot() {}

auto Robot::set(double x, double y) -> void {
  this->x = x;
  this->y = y;
}

auto Robot::getX() const -> double {
  return x;
}

auto Robot::getY() const -> double {
  return y;
}

auto Robot::move(double dx, double dy) -> void {
  x += dx;
  y += dy;
}

auto Robot::show() const -> void {
  printf("(x, y) = (%5.3f, %5.3f)\n", x, y);
}
 

 

main.cpp


#include "robot.hpp"

auto main() -> int {
  //Robot robot;
  //Robot robot{0, 0};
  Robot robot = {0, 0};
  robot.move(1, 1);
  robot.show();

  //auto robot0 = Robot; /* NG */
  //auto robot0 = Robot();
  //auto robot0 = Robot(0, 0);
  auto robot0 = Robot{0, 0};
  robot0.move(1, 1);
  robot0.show();

  //auto robot1 = new Robot;
  //auto robot1 = new Robot();
  //auto robot1 = new Robot(0, 0);
  auto robot1 = new Robot{0, 0};
  robot1->move(1, 1);
  robot1->show();
  delete robot1;

  const int length = 10;
  Robot robot00[length];
  //Robot robot00[Robot::robots]; /* NG */
  for (int i = 0; i < length; i++) {
    robot00[i] = {0, 0};
    robot00[i].move(1, 1);
    robot00[i].show();
  }

  auto robot11 = new Robot[Robot::robots];
  for (int i = 0; i < Robot::robots; i++) {
    robot11[i] = {0, 0};
    robot11[i].move(1, 1);
    robot11[i].show();
  }
  delete[] robot11;
}
 

 

コンパイル


g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static *.cpp -o main.exe
strip main.exe

 

コンパイル


g++ -std=c++17 -O3 -pedantic-errors -s -Wall -c robot.cpp -o robot.o
g++ -std=c++17 -O3 -pedantic-errors -s -Wall -static robot.o main.cpp -o main.exe
strip main.exe


参考サイト

 

C言語によるオブジェクト指向風プログラミング

以下のコードは、構造体のメンバが公開されるオブジェクト指向風プログラミングのコード例です。

 

robot.h

#ifndef ROBOT_H
#define ROBOT_H

typedef struct {
  double x;
  double y;
} Robot;

extern Robot* newRobot(void);
extern void deleteRobot(Robot*);
extern void setRobot(Robot*, double, double);
extern double getxRobot(Robot*);
extern double getyRobot(Robot*);
extern void moveRobot(Robot*, double, double);
extern void printRobot(Robot*);

#endif
 

 

robot.c

#include "robot.h"
#include <stdio.h>
#include <stdlib.h>

Robot* newRobot(void) {
  return malloc(sizeof(Robot));
}

void deleteRobot(Robot* robotp) {
  free(robotp);
}

void setRobot(Robot* robotp, double x, double y) {
  robotp->x = x;
  robotp->y = y;
}

double getxRobot(Robot* robotp) {
  return robotp->x;
}

double getyRobot(Robot* robotp) {
  return robotp->y;
}

void moveRobot(Robot* robotp, double dx, double dy) {
  robotp->x += dx;
  robotp->y += dy;
}

void printRobot(Robot* robotp) {
  printf("x = %f\n", robotp->x);
  printf("y = %f\n", robotp->y);
}
 

 

main.c

#include "robot.h"

int main(void) {
  Robot* robotp = newRobot();
  setRobot(robotp, 0, 0);
  moveRobot(robotp, 1, 1);
  printRobot(robotp);
  deleteRobot(robotp);
}
 

以下のコードは、構造体のメンバが隠蔽されるオブジェクト指向風プログラミングのコード例です。

 

robot.h

#ifndef ROBOT_H
#define ROBOT_H

typedef struct robot Robot;

extern Robot* newRobot(void);
extern void deleteRobot(Robot*);
extern void setRobot(Robot*, double, double);
extern double getxRobot(Robot*);
extern double getyRobot(Robot*);
extern void moveRobot(Robot*, double, double);
extern void printRobot(Robot*);

#endif
 

 

robot.c

#include "robot.h"
#include <stdio.h>
#include <stdlib.h>

struct robot {
  double x;
  double y;
};

Robot* newRobot(void) {
  return malloc(sizeof(Robot));
}

void deleteRobot(Robot* robotp) {
  free(robotp);
}

void setRobot(Robot* robotp, double x, double y) {
  robotp->x = x;
  robotp->y = y;
}

double getxRobot(Robot* robotp) {
  return robotp->x;
}

double getyRobot(Robot* robotp) {
  return robotp->y;
}

void moveRobot(Robot* robotp, double dx, double dy) {
  robotp->x += dx;
  robotp->y += dy;
}

void printRobot(Robot* robotp) {
  printf("x = %f\n", robotp->x);
  printf("y = %f\n", robotp->y);
}
 

 

main.c

#include "robot.h"

int main(void) {
  Robot* robotp = newRobot();
  setRobot(robotp, 0, 0);
  moveRobot(robotp, 1, 1);
  printRobot(robotp);
  deleteRobot(robotp);
}
 

CとJavaによるオブジェクト指向プログラミング

〈プログラミングの原則〉
一つのプログラムの中に同じようなコードを重複して記述しないこと!


オブジェクト:変数(variable)とその変数を操作する関数(function)の集まり。状態(state)と動作(behaviour)を有する対象。

クラスは鋳型で、インスタンスはクラスから生成される鋳物です。複数のインスタンスをクラスから生成することができます。
オブジェクト指向プログラミングは、以下の場合に用いられます。

  - 変数を複数の関数で共有する場合
  - 状態遷移や状態に依存する関数を記述する場合
  - 2種類の変数に依存する関数を、引数とメンバー変数の関数として表現する場合

注)クラスは、変数や関数を分類するための一種の名前空間です。
注)クラスとインスタンスを総称してオブジェクト(object)と呼ぶことがあります。
注)C++ではメンバー変数(member variable)が、Javaではフィールド(field)が、オブジェクトの状態を表します。
注)手続き型プログラミングは、プログラムの中に頻繁に現れるステートメント(statement)の集まり(手続き)をサブルーチン(subroutine)として再利用するプログラミング技法のことです。
注)オブジェクト指向プログラミングは、関連する変数と手続き(procedure)の集まりをオブジェクト(object)として再利用するプログラミング技法のことです。


以下の例のように、C言語グローバル変数や参照渡しを使ったプログラムは、オブジェクト指向プログラミングで書き換えることができます。


C言語によるオブジェクト指向風プログラミング(複数のインスタンスを生成できない)

robot.h

#pragma once

//extern double x, y;
extern void setRobot(double, double);
extern void moveRobot(double, double);
extern void printRobot(void);
 

 

robot.c

#include <stdio.h>

static double x, y;

void setRobot(double x0, double y0) {
  x = x0;
  y = y0;
}

void moveRobot(double dx, double dy) {
  x += dx;
  y += dy;
}

void printRobot(void) {
  printf("x = %f\n", x);
  printf("y = %f\n", y);
}
 

 

main.c

#include "robot.h"

int main(void) {
  setRobot(0, 0);
  moveRobot(1, 1);
  printRobot();
}
 

C言語によるオブジェクト指向風プログラミング(複数のインスタンスを生成できる)

robot.h

#pragma once

typedef struct {
  double x, y;
} Robot;

extern void setRobot(Robot*, double, double);
extern void moveRobot(Robot*, double, double);
extern void printRobot(Robot*);
 

 

robot.c

#include "robot.h"
#include <stdio.h>

void setRobot(Robot* robotp, double x, double y) {
  robotp->x = x;
  robotp->y = y;
}

void moveRobot(Robot* robotp, double dx, double dy) {
  robotp->x += dx;
  robotp->y += dy;
}

void printRobot(Robot* robotp) {
  printf("x = %f\n", robotp->x);
  printf("y = %f\n", robotp->y);
}
 

 

main.c

#include "robot.h"

int main(void) {
  Robot robot1;
  setRobot(&robot1, 0, 0);
  moveRobot(&robot1, 1, 1);
  printRobot(&robot1);

  Robot robot2;
  setRobot(&robot2, 0, 0);
  moveRobot(&robot2, 2, 2);
  printRobot(&robot2);
}
 

Javaによるオブジェクト指向プログラミング

robot.java

class Robot {
  double x, y;

  void set(double x, double y) {
    this.x = x;
    this.y = y;
  }

  void move(double dx, double dy) {
    x += dx;
    y += dy;
  }

  void print() {
    System.out.println("x = " + x);
    System.out.println("y = " + y);
  }
}
 

 

main.java

class Main {
  public static void main(String... args) {
    Robot robot1 = new Robot();
    robot1.set(0, 0);
    robot1.move(1, 1);
    robot1.print();

    Robot robot2 = new Robot();
    robot2.set(0, 0);
    robot2.move(2, 2);
    robot2.print();
  }
}
 

参考サイト

 

アセンブリのお勉強

検索と置換!
転送命令、分岐命令、比較命令があれば、どんな演算でも新たに作ることができます!

以下では、Intel syntax に従います。また、CPU は 16bit とします。


0.Instruction

Instruction = Opcode (Operation Code) + Operands

Operand:immediate value, register, memory, I/O port


1.Move Instruction (Transfer Instruction)

1-1.Unconditional Move Instruction

 

move.asm

  mov destination, source ;transfer source to destination
 

 

1-2.Conditional Move Instruction

cmoveとcmovz、cmovneとcmovnzのマシーンコードは同じです。

 

cmove.asm

  cmove  destination, source ;zf == 1 → transfer source to destination
  cmovne destination, source ;zf == 0 → transfer source to destination
 

 

1-3.PUSH Instruction and POP Instruction

PUSH命令及びPOP命令は、転送命令の一つです。

〈PUSH命令の流れ〉
0)PUSH命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(PUSH命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)PUSH命令が実行されると、スタックポインタがスタックに積み込むデータのサイズ(operand-size attribute)だけディクリメントする。
2)スタックポインタが指す位置にオペランド(source)のサイズだけデータが積み込まれる。

〈POP命令の流れ〉
0)POP命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(POP命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)POP命令が実行されると、スタックポインタが指す位置からオペランドdestination)のサイズだけデータが取り出される。
2)スタックポインタがスタックから取り出したデータのサイズ(operand-size attribute)だけインクリメントする。

 

push.asm

  push source     ;transfer source to [sp]
  pop destination ;transfer [sp] to destination
 

 

1-4.I/O Instruction

I/O命令は、CPUのレジスタとI/Oポート間の転送命令です。destination 及び source にはレジスタを指定し、port-address は、即値またはレジスタで指定します。 尚、[port-address] は、port-address で指定されたI/Oポートを表します。

 

io.asm

  in destination, port-address ;transfer [port-address] to destination
  out port-address, source     ;transfer source to [port-address]
 

2.Jump Instruction (Branch Instruction)

ジャンプ命令は、インストラクションポインタ(ip)への転送命令です。

2-1.Unconditional Jump Instruction

 

jump.asm

  jmp source ;set ip to source
 

 

2-2.Conditional Jump Instruction

jeとjz、jneとjnzのマシーンコードは同じです。

 

cjump.asm

  je  source ;zf == 1 → set ip to source
  jne source ;zf == 0 → set ip to source
 

 

jcxz は、cx が 0 でなければ何もせず、cx が 0 になればオペランドにジャンプします。

 

jcxz.asm

start:
  mov cx 10

loop:
  ・・・・・・・
  dec cx
  jcxz break ;cx == 0 → jump to break
  jmp loop:

break:
  ・・・・・・・
 

 

2-3.Unconditional Loop Instruction with Count Register

loop は、cx をディクリメントした後、cx が 0 でなければオペランドにジャンプし、cx が 0 になればループを抜けます。

 

loop.asm

  loop source ;cx--, cx != 0 → set ip to source
 

 

loop1.asm

start:
  mov cx 10

label:
  ・・・・・・・
  loop label

  ・・・・・・・
 

 

2-4.Conditional Loop Instruction with Count Register

loopeとloopz、loopneとloopnzのマシーンコードは同じです。

 

cloop.asm

  loope  source ;cx--, cx != 0 and zf == 1 → set ip to source
  loopne source ;cx--, cx != 0 and zf == 0 → set ip to source
 

 

2-5.CALL Instruction and RET Instruction

CALL命令及びRET命令は、ジャンプ命令の一つです。

〈CALL命令の流れ〉
0)CALL命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(CALL命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)CALL命令が実行されると、インストラクションポインタの値がスタックに転送される。(インストラクションポインタがプッシュされる)
2)呼び出し先のアドレス(CALL命令のオペランド)がインストラクションポインタにセットされる。

〈RET命令の流れ〉
0)RET命令の実行前にインストラクションポインタが命令長分だけインクリメントする。(RET命令の次の命令のアドレスがインストラクションポインタにセットされる)
1)RET命令が実行されると、スタックの値がインストラクションポインタに転送される。(インストラクションポインタにポップされる)

 

サブルーチンでレジスタを使用するときは、次の例ようにPUSH命令で使用するレジスタの値を一旦スタックに退避(save)させておき、レジスタを使い終わったらPOP命令で元の値に復元(restore)します。 また、PUSHA命令、POPA命令は、それぞれ全てのレジスタをPUSH、POSする命令です。

 

call1.asm

start:
  call sub1
  call sub2

sub1:
  push ax
  push bx
  push cx
  mov ax, 0
  mov bx, 0
  mov cx, 0
  pop cx
  pop bx
  pop ax
  ret

sub2:
  pusha
  ・・・・・・・
  popa
  ret
 

 

次の例では、スタックを使ってサブルーチンに値を渡しています。(レジスタやメモリを使ってサブルーチンに値を渡すこともできます)

 

call2.asm

main:
  push 3 ;sp-=2
  push 2 ;sp-=2
  push 1 ;sp-=2
  call addxyz ;sp-=2

addxyz:
  push bp ;sp-=2
  mov bp, sp
  mov ax, [bp+4]
  add ax, [bp+6]
  add ax, [bp+8]
  mov sp, bp
  pop bp
  ret
 


call2.c

short addxyz(short x, short y, short z) {
  return x + y + z;
}

int main(void) {
  addxyz(1, 2, 3);
}
 

 

2-6.Software Interrupt Instruction

ソフトウェア割り込み命令は、ジャンプ命令の一つです。INT命令及びIRET命令は、それぞれCALL命令及びRET命令に対応しています。

 

int.asm

  int (interrupt number)
  int 0x21 ;DOS System Call
  int 0x80 ;Linux System Call
  iret
 

3.Compare Instruction

 

compare.asm

  cmp ax, 0
  cmp ax, bx
  cmp ax, [0x0000]
  cmp source1, source2
 
  ZF CF
source1 < source2 0 1
source1 == source2 1 0
source1 > source2 0 0


<Equality Comparator XNOR>

X XNOR Y ≡ (X∧Y)∨(¬X∧¬Y)


4.Other Instructions

4-1.Increment Instruction and Decrement Instruction

 

increment.asm

  inc state ;state + 1 -> state
  dec state ;state - 1 -> state
 

 

4-2.Arithmetic Instruction

 

arithmetic.asm

  add state, source ;state + source -> state
  sub state, source ;state - source -> state
  mul state, source ;state * source -> state
  div state, source ;state / source -> state
 

 

4-3.Logic Instruction

 

logic.asm

  not state         ;¬ state -> state
  and state, source ;state ∧ source -> state
  or  state, source ;state ∨ source -> state
 

 

4-4.Bit Manipulation Instruction (Bit Shift Instruction and Bit Rotate Instruction)

 

bitmanipulation.asm

  shl state, count
  shr state, count
  rol state, count
  ror state, count
 

 

4-5.No Operation Instruction and Halt Instruction

 

nop.asm

  nop
  hlt
 

Appendix

A-1.Addressing Mode

Address Space:memory address space, I/O address space
Addressing Mode:immediate addressing, absolute addressing, ralative addressing, direct addressing, indirect addressing

 

A-2.I/O Controller (Device Controller)

Processor ⇔ I/O Controller (Device Controller) ⇔ I/O Device (Peripheral Device)

I/O Controller:status register、command register (control register)、input register、output register


参考サイト