C++における参照

reference.cpp

#include <iostream>

class Point {
  double X;
public:
  double& x() {
    return X;
  }
/* NG
  const double& getx() {
    return X;
  }
*/
/* NG
  double& getx() const {
    return X;
  }
*/
};

int main() {
  Point point;
  point.x() = 0;
  std::cout << point.x() << std::endl;
  return 0;
}

広告

Servletを使ったWebアプリケーション

JavaのJSPとServletを使ったWebアプリケーションのサンプルを紹介します。サーブレットコンテナはJettyを用いています。まず、webappsフォルダの直下に好きな名前のフォルダ(今回の例ではwebapp)を作成し、WEB-INFフォルダにweb.xmlを置いて下さい。web.xmlは下記のすべてのサンプルで共通です。

D:\jetty\webapps\webapp\WEB-INF\web.xml

<web-app>
  <servlet>
    <servlet-name>servlet</servlet-name>
    <servlet-class>Servlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>servlet</servlet-name>
    <url-pattern>/servlet</url-pattern>
  </servlet-mapping>
</web-app>

次に、下記のjavac0.batを使ってServlet.javaをコンパイルした後、Servlet.classをD:\jetty\webapps\webapp\WEB-INF\classesの直下に置きます。

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

set JAVA_HOME=D:\jdk
set path=%JAVA_HOME%\bin
javac -classpath D:\jetty\lib\servlet-api-3.1.jar *.java

Jettyの起動は以下のようにします。

start.bat

set JAVA_HOME=D:\jdk
set path=%JAVA_HOME%\bin
cd /d D:\jetty
java -jar start.jar


1.Servletを直接呼び出すサンプル

Jettyを起動し、WebブラウザのURLに

http://localhost:8080/webapp/servlet

と入力すればServlet.classを直接呼び出すことができます。

D:\jetty\webapps\webapp\WEB-INF\src\Servlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Servlet extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<body>");
    out.println("Welcome to Servlet!");
    out.println("</body>");
    out.println("</html>");
  }
}


2.JSPからServletを呼び出すサンプル

input.jspとoutput.jspをwebappの直下に置いた後、Jettyを起動し、WebブラウザのURLに

http://localhost:8080/webapp/input.jsp

と入力すればJSPからServlet.classを呼び出すことができます。

D:\jetty\webapps\webapp\input.jsp

<%@ page contentType="text/html; charset=Shift_JIS" %>
<html>
<body>
<form action="/webapp/servlet" method="post">
<input type="submit" value="実行">
<input type="text" name="input1">
<input type="text" name="input2">
</form>
</body>
</html>

D:\jetty\webapps\webapp\WEB-INF\src\Servlet.java

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Servlet extends HttpServlet {
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    request.setCharacterEncoding("Shift_JIS");
    response.setCharacterEncoding("Shift_JIS");
    //response.setContentType("text/html; charset=Shift_JIS");
    String parameter1 = request.getParameter("input1");
    String parameter2 = request.getParameter("input2");
    request.setAttribute("output", parameter1 + parameter2);
    request.getRequestDispatcher("/output.jsp").forward(request, response);
  }
}

D:\jetty\webapps\webapp\output.jsp

<%@ page contentType="text/html; charset=Shift_JIS" %>
<html>
<body>
<%= request.getAttribute("output") %>
</body>
</html>


3.Servletからデータベースを操作するサンプル

このサンプルではMySQLを用いています。まず、MySQL Community ServerMySQL Connector/J(MySQL用のJDBCドライバ)をダウンロードしインストールします。
MySQL Connector(mysql-connector-java-*.*.*-bin.jar)は、D:\jetty\webapps\webapp\WEB-INF\libの直下に置いて下さい。
続いて、コマンドプロンプトからmysqldを起動します。


>set path=D:\mysql\bin
>mysqld

更に別のコマンドプロンプトから以下のように入力すれば、データベース(database0)やテーブル(table0)を作成することができます。


>set path=D:\mysql\bin
>mysql -u root
mysql> set character_set_database = utf8;
mysql> show variables like 'char%';
mysql> create database database0;
mysql> show databases;
mysql> alter database database0 character set utf8;
mysql> show create database database0;
mysql> use database0;
mysql> create table database0.table0(id int, password varchar(100));
mysql> show tables from database0;
mysql> describe table0;
mysql> alter table table0 convert to character set utf8;
mysql> show create table table0;
mysql> desc table0;
mysql> insert into table0 (id, password) values (1, 'p1');
mysql> insert into table0 (id, password) values (2, 'p2');
mysql> insert into table0 (id, password) values (3, 'p3');
mysql> select * from table0;
mysql> delete from table0;
mysql> drop table table0;
mysql> CREATE USER xxxxx IDENTIFIED BY 'pass0';
mysql> GRANT ALL ON *.* TO sample@localhost IDENTIFIED BY "password";
mysql> SET PASSWORD FOR xxxxx@"%"=PASSWORD('pass0');
mysql> select Host, User, Password from mysql.user;
mysql> delete from mysql.user where user='user0';
mysql> exit

尚、MySQLサーバをシャットダウンする場合は以下のように入力して下さい。今回の場合は起動したままにしておいて下さい。


>set path=D:\mysql\bin
>mysqladmin -u root shutdown

次に、Jettyを起動し、WebブラウザのURLに

http://localhost:8080/webapp/servlet

と入力すればServlet.classが起動し、サーブレットからMySQLを操作することができます。

D:\jetty\webapps\webapp\WEB-INF\src\Servlet1.java

import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Servlet extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<body>");
    String url = "jdbc:mysql://localhost:3306/database0?useUnicode=true&characterEncoding=UTF-8";
    String user = "root";
    String password = "";
    Connection connection = null;
    Statement statement = null;
    ResultSet resultSet = null;
    try {
      Class.forName("com.mysql.jdbc.Driver").newInstance();
      connection = DriverManager.getConnection(url, user, password);
      statement = connection.createStatement();
      String sql = "";
      int numResults = 0;

      sql = "insert into table0 (id, password) values (5, 'p5')";
      numResults = statement.executeUpdate(sql);

      sql = "update table0 set password = 'q1' where id = 1";
      numResults = statement.executeUpdate(sql);

      sql = "delete from table0 where id = 2";
      numResults = statement.executeUpdate(sql);

      sql = "select * from table0 order by id limit 1000";
      resultSet = statement.executeQuery(sql);
      while (resultSet.next()) {
        out.println("<p>" + resultSet.getInt(1) + "," + resultSet.getString(2) + "</p>");
        out.println("<p>" + resultSet.getInt("id") + "," + resultSet.getString("password") + "</p>");
      }
    }
    catch (ClassNotFoundException e) {
      out.println(e.getMessage());
    }
    catch (SQLException e) {
      out.println(e.getMessage());
    }
    catch (Exception e) {
      out.println(e.getMessage());
    }
    finally {
      try {
        if (resultSet != null) resultSet.close();
        if (statement != null) statement.close();
        if (connection != null) connection.close();
      }
      catch (SQLException e) {
        out.println(e.getMessage());
      }
      catch (Exception e) {
        out.println(e.getMessage());
      }
    }
    out.println("</body>");
    out.println("</html>");
  }
}


4.PreparedStatementを使ったサンプル

D:\jetty\webapps\webapp\WEB-INF\src\Servlet2.java

import java.io.*;
import java.sql.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class Servlet extends HttpServlet {
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.println("<html>");
    out.println("<body>");
    String url = "jdbc:mysql://localhost:3306/database0?useUnicode=true&characterEncoding=UTF-8";
    String user = "root";
    String password = "";
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    try {
      Class.forName("com.mysql.jdbc.Driver").newInstance();
      connection = DriverManager.getConnection(url, user, password);
      String sql = "";
      int numResults = 0;

      sql = "insert into table0 (id, password) values (?, ?)";
      preparedStatement = connection.prepareStatement(sql);
      preparedStatement.setInt(1, 5);
      preparedStatement.setString(2, "a5");
      numResults = preparedStatement.executeUpdate();

      sql = "update table0 set password = ? where id = ?";
      preparedStatement = connection.prepareStatement(sql);
      preparedStatement.setString(1, "b1");
      preparedStatement.setInt(2, 1);
      numResults = preparedStatement.executeUpdate();

      sql = "delete from table0 where id = ?";
      preparedStatement = connection.prepareStatement(sql);
      preparedStatement.setInt(1, 2);
      numResults = preparedStatement.executeUpdate();

      sql = "select * from table0 order by id limit 1000";
      preparedStatement = connection.prepareStatement(sql);
      resultSet = preparedStatement.executeQuery();
      while (resultSet.next()) {
        out.println("<p>" + resultSet.getInt(1) + "," + resultSet.getString(2) + "</p>");
        out.println("<p>" + resultSet.getInt("id") + "," + resultSet.getString("password") + "</p>");
      }
    }
    catch (ClassNotFoundException e) {
      out.println(e.getMessage());
    }
    catch (SQLException e) {
      out.println(e.getMessage());
    }
    catch (Exception e) {
      out.println(e.getMessage());
    }
    finally {
      try {
        if (resultSet != null) resultSet.close();
        if (preparedStatement != null) preparedStatement.close();
        if (connection != null) connection.close();
      }
      catch (SQLException e) {
        out.println(e.getMessage());
      }
      catch (Exception e) {
        out.println(e.getMessage());
      }
    }
    out.println("</body>");
    out.println("</html>");
  }
}


参考サイト

1.Jettyインストール / ファイルとフォルダの配置 / JSP起動
2.ざっくりJava JSP/サーブレット
3.サーバサイドJava入門(サーブレット編)
4.ど素人のJava入門(サーブレット編)
5.JSPの基本構文を理解する
6.JSPとサーブレットのキャッチボール
7.JSPとのデータ受渡し
8.サーブレットからのJSPの呼び出し
9.サーブレットにおけるセッション管理
10.JSPからサーブレットへのデータの受け渡しについて
11.JSPの基本「暗黙オブジェクト」を使う
12.Servlet から JDBC を使う
13.JavaでのStatement/ResultSetのクローズ
14.PreparedStatementを使ったサンプル

Javaによる多態性

抽象メソッド(本体を持たないメソッド)を持つクラスを抽象クラスと呼びます。

main.java

abstract class Parent {
  abstract void print();
}

class Child1 extends Parent {
  void print() {
    System.out.println("Child1");
  }
}

class Child2 extends Parent {
  void print() {
    System.out.println("Child2");
  }
}

class Main {
  public static void main(String... args) {
    Parent p1 = new Child1();
    Parent p2 = new Child2();
    p1.print();
    p2.print();
  }
}

C++による多態性

main.cpp

#include <iostream>

class Parent {
public:
  virtual void print() = 0;
};

class Child1 : public Parent {
public:
  void print() {
    std::cout << "Child1" << std::endl;
  }
};

class Child2 : public Parent {
public:
  void print() {
    std::cout << "Child2" << std::endl;
  }
};

int main() {
  Parent* p1 = new Child1;
  Parent* p2 = new Child2;
  p1->print();
  p2->print();
  return 0;
}

C/C++で周期的処理

下記のプログラムはCygwinでコンパイルしています。


1.Cの場合

sleep.c

#include <stdio.h>
#include <unistd.h>

int main(void) {
  int i = 0;
  for (;;) {
    printf("%d\n", i);
    sleep(1);
    i++;
  }
  return 0;
}


$ gcc -std=c11 -O2 -Wall *.c -o sleep.exe
$ ./sleep


2.C++の場合

C++では、C++11以降、sleep_for関数を使って周期的処理を行うことができるようになりました。

sleep.cpp

#include <chrono>
#include <iostream>
#include <thread>

int main() {
  int i = 0;
  for (;;) {
    std::cout<< i << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    i++;
  }
  return 0;
}


$ g++ -std=c++11 -O2 -Wall *.cpp -o sleep.exe
$ ./sleep


参考サイト

1.sleep系関数の精度と挙動
2.VC++の sleep_for 関数の実装がよろしくない
3.一定時間処理を停止する

C/C++における配列長の決定タイミング

Cでは、C99以降、実行時(run time)に配列の長さを決定できるようになりましたが、C++ではコンパイル時(compile time)に配列の長さを決定する必要があります。


1.Cの場合

array.c

#include <stdio.h>

int main(void) {
  int length = 10;
  double array[length];
  for (int i = 0; i < length; i++) {
    array[i] = 0;
    printf("%f\n", array[i]);
  }
  return 0;
}

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

set PATH=D:\LLVM\bin;D:\MinGW\bin
clang -std=c11 -O2 -Wall *.c -o main.exe


2.C++の場合

array.cpp

#include <cstdio>

int main() {
  const int length = 10;
  double array[length];
  for (int i = 0; i < length; i++) {
    array[i] = 0;
    printf("%f\n", array[i]);
  }
  return 0;
}

clang++0.bat(ファイル名をclang++.batにすると暴走します)

set PATH=D:\LLVM\bin;D:\MinGW\bin
clang++ -std=c++11 -O2 -Wall *.cpp -o main.exe


参考サイト

1.プログラミング言語Cの新機能 可変長配列
2.C言語(C99)の variable length array というものを初体験

C/C++における多重定義エラー

構造体の場合は、同じファイルで同じ構造体を二度定義すると多重定義(multiple definition)エラーになりますが、異なるファイルで同じ構造体を定義しても多重定義エラーにはなりません。
一方、グローバル変数や関数の場合は、異なるファイルで同じ定義をすると多重定義エラーになります。

main.cpp

struct A {
  int i;
};
/*
struct A {
  int i;
};
*/

extern int i;
extern int i;

void f();
void f();

void g();

int main() {
  A a;
/* C
  struct A a;
*/
  a.i = 0;
  f();
  return 0;
}

sub1.cpp

struct A {
  double x;
};

int i;

void f() {}

sub2.cpp

struct A {
  double x;
};

//int i;

//void f() {}


参考サイト

1.C++ ファイルを分けよう
2.C++ ファイル分割と重複定義
3.When can I use a forward declaration?
4.What is the difference between a definition and a declaration?