Why do you need to type indents in your code

try to keep indents for each lines
if you just type
   it is very difficult to read
     so it is harder for you 
     else if it is not hard to read for you
   it may take more time to understand 
   and it is also hard to someone else 
    like teachers or yourself, 
      a month later, you may forget your source
even if you just copy and paste from google results,
  if you try to make indents, 
    you may understand it better.
then you need to make indents.

Here is an example :-)

プログラミングを学ぶ人間が首相になるのはすばらしい

■シンガポール首相、自作のプログラミングコードをFacebookで公開
http://wired.jp/2015/05/08/prime-minister-of-singapore/

プログラミングを学ぶ人間が首相になるのはすばらしい。
しかもゲームのソルバー(解法発見器)。

人間にやらせるべきこと、機械にやらせるべきことの違いを若いうちに学んだ人間は、
人間こそがやるべきことを見極めている。

この世に生を受けてからいままで、他人が作ったゲームしかやったことがない人は
実は他人が作った世界の中でしか生きていない。
君は「ゲームを解くゲーム」を解くコンピュータを作れるか。
ゲームを作る側はその世界をデバッグしなければならないから
もちろん解く為のツールを作る。

そういえばICUの学生に2048やパズドラのクローンを書かせたことがある。
いろんなことがわかる。
KAITの学生にもたくさんコードを書かせている。

彼らが将来、首相になったら、Githubアカウントを公開するべきだと思う。

Google APIをつかってみる(初歩の初歩編)

ふとしたことからYouTubeAPIを使う必要が出てきたので、Google APIを久々に触ってみる。

作りたいものはYouTubeで自分がアップロードした動画のリストなどを取得するC#.NETで開発したスタンドアロンアプリ。

一気に解説するのは大変そうなのと、このあたりを解説している日本語ページがまったくなかったで、まずは導入編から。

〔参考資料〕

Google APIs Client Library for .NET (本家)
https://developers.google.com/api-client-library/dotnet/get_started

書いてあるとおりで動くなら問題ないのだけど、動かないので。

ちなみに以下、開発環境はVisual Studio 2010です。

具体的にはスレッド周りのコードが動きません、たぶん.NETが古いからコンパイルできない。

http://www.atmarkit.co.jp/ait/articles/1109/30/news126.html

以下、実際に動いたソース。コンソールアプリの新規プロジェクト作成ウィザードからべたっとはりつけてしまっても動くはずです。

[csharp]
using System;
using Google.Apis.Discovery.v1;
using Google.Apis.Discovery.v1.Data;
using Google.Apis.Services;

namespace Discovery.ListAPIs
{
class Program
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Discovery API Sample");
Console.WriteLine("====================");
try
{
// new Program().Run().Wait();
new Program().Run();
}
catch (AggregateException ex)
{
foreach (var e in ex.InnerExceptions)
{
Console.WriteLine("ERROR: " + e.Message);
}
}
Console.WriteLine("Press any key to continue…");
Console.ReadKey();
}

// private async Task Run()
private void Run()
{
// Create the service.
var service = new DiscoveryService(new BaseClientService.Initializer
{
ApplicationName = "Discovery Sample"
//,
// APIKey = "[API Key]", //今回は必要ない
});

// Run the request.
Console.WriteLine("Executing a list request…");
// var result = await service.Apis.List().ExecuteAsync();
var result = service.Apis.List().ExecuteAsync();

// Display the results.
if (result.Result.Items != null)
{
foreach (DirectoryList.ItemsData api in result.Result.Items)
{
Console.WriteLine(api.Id + " – " + api.Title);
}
}
}
}
}

[/csharp]

コメントアウトしているところは、本家GoogleAPIのサイトでは非同期関数で実装しているところを、わかりやすく普通の関数で実装しなおしている部分です。

なお、ビルドを通すためにはNuGetを使って必要なライブラリを追加していく必要があります。
NuGetのVisual Studioへのインストールはこちらをご参考。
http://www.atmarkit.co.jp/fdotnet/chushin/nuget_01/nuget_01_01.html
NuGetで管理できるGoogle APIでどんなライブラリが存在するかはこちらのリンクがわかりやすいです。
NuGetでパッケージ管理できるGoogleAPI一覧

具体的にはNuGetのパッケージマネージャで、以下のコマンドを使ってパッケージをインストールします。

PM> Install-Package Google.Apis
PM> Install-Package Google.Apis.Tasks.v1
PM> Install-Package Google.Apis.Discovery.v1

無事ビルドがとおり、実行すると、利用できるGoogle APIの一覧が表示できます。

Discovery API Sample
====================
Executing a list request...
adexchangebuyer:v1 - Ad Exchange Buyer API
adexchangebuyer:v1.1 - Ad Exchange Buyer API
adexchangebuyer:v1.2 - Ad Exchange Buyer API
adexchangebuyer:v1.3 - Ad Exchange Buyer API
adexchangeseller:v1 - Ad Exchange Seller API
adexchangeseller:v1.1 - Ad Exchange Seller API
adexchangeseller:v2.0 - Ad Exchange Seller API
admin:directory_v1 - Admin Directory API
admin:email_migration_v2 - Email Migration API v2
admin:reports_v1 - Admin Reports API
adsense:v1.2 - AdSense Management API
adsense:v1.3 - AdSense Management API
adsense:v1.4 - AdSense Management API
adsensehost:v4.1 - AdSense Host API
analytics:v2.4 - Google Analytics API
analytics:v3 - Google Analytics API
androidpublisher:v1 - Google Play Android Developer API
androidpublisher:v1.1 - Google Play Android Developer API
androidpublisher:v2 - Google Play Android Developer API
appsactivity:v1 - Google Apps Activity API
appstate:v1 - Google App State API
audit:v1 - Enterprise Audit API
autoscaler:v1beta2 - Google Compute Engine Autoscaler API
bigquery:v2 - BigQuery API
blogger:v2 - Blogger API
blogger:v3 - Blogger API
books:v1 - Books API
calendar:v3 - Calendar API
civicinfo:us_v1 - Google Civic Information API
civicinfo:v1 - Google Civic Information API
civicinfo:v2 - Google Civic Information API
cloudmonitoring:v2beta1 - Cloud Monitoring API
compute:v1 - Compute Engine API
content:v2 - Content API for Shopping
coordinate:v1 - Google Maps Coordinate API
customsearch:v1 - CustomSearch API
datastore:v1beta1 - Google Cloud Datastore API
datastore:v1beta2 - Google Cloud Datastore API
dfareporting:v1 - DFA Reporting API
dfareporting:v1.1 - DFA Reporting API
dfareporting:v1.2 - DFA Reporting API
dfareporting:v1.3 - DFA Reporting API
discovery:v1 - APIs Discovery Service
dns:v1beta1 - Google Cloud DNS API
doubleclickbidmanager:v1 - DoubleClick Bid Manager API
doubleclicksearch:v2 - DoubleClick Search API
drive:v1 - Drive API
drive:v2 - Drive API
freebase:v1-sandbox - Freebase Search
freebase:v1sandbox - Freebase Search
freebase:v1 - Freebase Search
fusiontables:v1 - Fusion Tables API
games:v1 - Google Play Game Services API
gamesManagement:v1management - Google Play Game Services Management API
gan:v1beta1 - Google Affiliate Network API
genomics:v1beta - Genomics API
gmail:v1 - Gmail API
groupsmigration:v1 - Groups Migration API
groupssettings:v1 - Groups Settings API
identitytoolkit:v3 - Google Identity Toolkit API
licensing:v1 - Enterprise License Manager API
manager:v1beta2 - Deployment Manager API
mapsengine:exp2 - Google Maps Engine API
mapsengine:v1 - Google Maps Engine API
mirror:v1 - Google Mirror API
oauth2:v1 - Google OAuth2 API
oauth2:v2 - Google OAuth2 API
pagespeedonline:v1 - PageSpeed Insights API
plus:v1 - Google+ API
plusDomains:v1 - Google+ Domains API
prediction:v1.2 - Prediction API
prediction:v1.3 - Prediction API
prediction:v1.4 - Prediction API
prediction:v1.5 - Prediction API
prediction:v1.6 - Prediction API
pubsub:v1beta1 - Cloud Pub/Sub API
qpxExpress:v1 - QPX Express API
replicapool:v1beta1 - Replica Pool API
reseller:v1sandbox - Enterprise Apps Reseller API
reseller:v1 - Enterprise Apps Reseller API
resourceviews:v1beta1 - Resource Views API
resourceviews:v1beta2 - Resource Views API
siteVerification:v1 - Google Site Verification API
spectrum:v1explorer - Google Spectrum Database API
sqladmin:v1beta1 - Cloud SQL Administration API
sqladmin:v1beta3 - Cloud SQL Administration API
storage:v1 - Cloud Storage API
storage:v1beta1 - Cloud Storage API
storage:v1beta2 - Cloud Storage API
taskqueue:v1beta1 - TaskQueue API
taskqueue:v1beta2 - TaskQueue API
tasks:v1 - Tasks API
translate:v2 - Translate API
urlshortener:v1 - URL Shortener API
webfonts:v1 - Google Fonts Developer API
webmasters:v3 - Webmaster Tools API
youtube:v3 - YouTube Data API
youtubeAnalytics:v1 - YouTube Analytics API
youtubeAnalytics:v1beta1 - YouTube Analytics API
Press any key to continue...

さてこれでYouTube Data API v3.0が利用できますね。

このあたりはまた今度。

 

追記:プロジェクトはGithubでも公開しておきましたので、ご活用ください。

https://github.com/kaitas/ShiraiLabOpen/tree/master/GoogleAPIs/GoogleAPIsListing

 

【C++言語】第7回「参照」new,delete,値渡し,ポインタ渡し,参照渡し

本アーティクルは「応用プログラミングA」の2013年5月28日の講義内容の補足です。
内容の正確さは保証しません。
これをそのままコピーしてレポートを書く人がいますが、全く勉強にならないのでやめましょう。

 

問題1「newとdelete」

前回、「C++でのポインタと配列の利用」ではクラスのオブジェクトをいきなり配列にとって、そのポインタを挿げ替えるような初期化を行っていたわけですが、ふつうは(少なくとも最近の言語は)こんな”野蛮な”オブジェクトの生成をしたりはしません。
(もちろんmallocやfreeなどもありますが…)

今回はnew演算子とdelete演算子を使った例を見てみましょう。

[code lang=”cpp”]
// 2013/5/28 Q1
/* new と delete 演算子
* 三角形を表す Triangle クラスのオブジェクトを、new 演算子を使って作成する。
* オブジェクトには初期値として、(3,4,5)を与える。
* 各辺の長さと長さと面積を出力した後に delete でメモリを開放する。
* なお、 delete 演算子によってデストラクタが呼び出されることを確認するために、
* デストラクタを追加している。
*/
#include <iostream>
#include <cmath>
using namespace std;
class Triangle {
double a, b, c; //辺の長さ
public:
//コンストラクタ
Triangle(double u, double v, double w) {
a = u; b = v; c = w;
}
//デストラクタ
~Triangle() {
cout << "デストラクタが呼び出されました\n";
}
void set_a(double x) { a = x; }
void set_b(double x) { b = x; }
void set_c(double x) { c = x; }
double get_a() {return a;}
double get_b() {return b;}
double get_c() {return c;}
double area(); //面積を求める関数
void show(); //結果を表示する
};
double Triangle::area() {
double s;
s = (a+b+c)/2.0f;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
void Triangle::show() {
cout << "辺a = " << a << "\n";
cout << "辺b = " << b << "\n";
cout << "辺c = " << c << "\n";
cout << "面積 = " << area() << "\n";
}

int main() {
Triangle *tri;
tri = new Triangle(3,4,5);
/* new演算子はコンストラクタを指定して新しいオブジェクトの実体のポインタを取得する */
/* 1行で書くとこんな感じ
Triangle *tri = new Triangle(3,4,5); */
tri->show();
delete tri;
return 0;
}
[/code]

new演算子を使うとメモリの動的確保が行えます。deleteはnewで確保したメモリを開放します。
newとdeleteは演算子でmalloc()やfree()は関数なので書式が異なります。
このサンプルでは

[code lang=”cpp”]
Triangle *tri;
tri = new Triangle(3,4,5);
[/code]

という書式で、コンストラクタを呼んでクラスのインスタンスを取得しています。

なおnew/deleteを使った配列の場合も覚えておきましょう。たとえばint型10個分の配列を動的確保する場合

[code lang=”cpp”]
int *p;
p = new int[10];
for (int i =0; i<10; i++ ) {
p[i] = i;
}
delete [] p; //このカッコの付き方に注意
[/code]

new演算子を使ってクラスのインスタンスを取得した場合、そのメンバ変数やメンバ関数にアクセスするときはアロー演算子(->)を使用します。

[code lang=”cpp”]
tri->show();
[/code]

 

問題2「値渡し、ポインタ渡し、参照渡し」

 
C++で関数にオブジェクトを渡す際に、「値渡し」、「ポインタ渡し」、「参照渡し(reference)」といった方法でオブジェクトを渡すことができます。問題2ではこれらを実験するプログラムを作成します。

[code lang=”cpp”]
// 2013/5/28 Q2
/* 値渡し、ポインタ渡し、参照渡し
*/
#include <iostream>
using namespace std;

class Coord {
double x,y,z;
public:
void set(double u,double v, double w) {
x = u; y = v; z = w;
}
void show();
};
void Coord::show() {
cout << "(" << x << "," << y << "," << z << ")";
}
//以下の関数はクラス内のメソッドではなく、オブジェクトの外でやり取りするオペレータ関数
//値渡し
void setCoord1(Coord ob) {
double u,v,w;
cout << "数字を3つ入力してください:";
cin >> u >> v >> w;
ob.set(u,v,w); //実際にはここで値は設定できないことに注意!
} //ここでobのスコープが終了するため、設定した値は消滅する。
//ここで生成されたオブジェクトの実体obはobjとは別のメモリ空間にいることに注意

//ポインタ渡し
void setCoord2(Coord *ob) {
//渡すときは"&obj"、受けるときは"*ob"と書く!
double u,v,w;
cout << "数字を3つ入力してください:";
cin >> u >> v >> w;
ob->set(u,v,w); //アロー演算子"->"をつかってメソッドset()を呼ぶ
} //ここでobのスコープが終了するため、設定した値は消滅する。
// obは消滅するが、実際のメモリ上のポインタが渡されているため、
// 処理と処理結果はobjに残る

//参照渡し
void setCoord3(Coord &ob) {
//参照渡しで受け取るときは"&ob"になる。なぜならポインタだから。
double u,v,w;
cout << "数字を3つ入力してください:";
cin >> u >> v >> w;
ob.set(u,v,w); //オブジェクトそのものがきているので、"."ドット演算子になる
}
//ここでobのスコープが終了するが….
//ポインタ渡しと同様、処理結果はobjに残る

int main() {
Coord obj;
obj.set(1.1, 2.3, 5.5);
cout << "オブジェクトの初期値:"; obj.show(); cout << "\n\n";

cout << "値渡しで関数にオブジェクトを渡します\n";
setCoord1(obj);
cout << "オブジェクトの値:"; obj.show(); cout << "\n\n";

cout << "ポインタ渡しで関数にオブジェクトを渡します\n";
setCoord2(&obj); //アンパサンドを使う scanf(&buf)と同じ!
//関数の入力ではなく受け取り容器
cout << "オブジェクトの値:"; obj.show(); cout << "\n\n";

cout << "参照渡しで関数にオブジェクトを渡します\n";
setCoord3(obj); //&がつかないので値渡しにそっくりだが、
//関数の実装での受け方が違います
cout << "オブジェクトの値:"; obj.show(); cout << "\n\n";

return 0;
}

[/code]

チャック・ノリス問題として出題してみたり。

わかりやすい解説
http://www.aerith.net/design/argument-j.html

問題3「参照渡しを用いた値の交換」トランプ問題

★レポート締切前なので未完です。

[code lang=”cpp”]
// 2013/5/28 Q3
/* トランプ問題
*/
#include
#include
using namespace std;

enum suit { SPADE, HEART, CLUB, DIAMOND } ;
class PCard {
//from the question
};
//参照渡し仮引数
void swap(PCard &ob1, PCard &ob2) {
PCard ob;
ob = ob1; ob1 = ob2; ob2 = ob;
}

int main() {
PCard deck[52];
for ( int i=0; i< 4; i++ ){ //suit
for (int j =1; j<= 13; j++ ){ //number
switch(i) {
case 0:
deck[i*13+j-1].set(SPADE, j);
break;
//★以下すべてのsuitに実施(未実装)
}
}
}
//カードの初期化終了
//内容一覧
for (int i=0; i<52; i++) {
deck[i].show();
}

//シャッフル
for (int i =0; i<100; i++) {
int a,b;
a = rand() % 52;
b = rand() % 52;
swap(deck[a], deck[b]);
//ここにAとBを入れ替えました、的な表示を入れておくとわかりやすい
}
//再度内容一覧
for (int i=0; i<52; i++) {
deck[i].show();
}

return 0;
}
[/code]

【C++】第6回:C++でのポインタと配列の利用

応用プログラミングA(C++言語)、前回の「C++のフレンド関数」に引き続き、今週は「C++でのポインタと配列の利用」です。

C++言語はオブジェクト指向(クラス指向)ではありますが、C言語のパワフルなポインタも使えることは意外と知られていません。
(とはいえ実用上はオブジェクトの配列を使うことが多いと思います)

今回は「学生の成績を管理するクラス」を作成して、ここまでの復習を兼ねた総合問題という設計になっています。

出題された課題は3問あります。
Q1、Q2、Q3…と順に解いていかないと、最後までたどり着けませんので注意です。

またサンプル中に出てくる学生の名前は昨年のAKB48からガラッと変わって『ラブライブ!』からの引用が多いようですが、打つのが大変なのと、私自身が思い入れがないので適当なボカロあたりの名前に差し替わっております。
このあたり、まるまるコピーした場合は減点対象となりますので要注意。

まずQ1です。

ここでは学生のデータを管理するStudentListクラスを作成します。

[code lang=”cpp”]
class StudentList {
char name[50]; //学生の氏名
int id, grade; //学籍番号、学年
public:
void set(char *n, int i, int g);
void show();
};
[/code]

このオブジェクトの配列に10人分のデータをコンソールから入力し、すべて入力し終わったらコンソールに出力する基本となるプログラムを作ります。

「独習C++(第4版)」の例4.2を参考にするとよいようです。
独習C++ 第4版

[code lang=”cpp”]
//配列とポインタ:クラスオブジェクトを配列でとった場合も、C言語におけるポインタと同様に扱える。
#include <iostream>
#include <cstring>
using namespace std;
class StudentList {
char name[50];
int id, grade;
public:
void set(char *n, int i, int g);
void show();
};
void StudentList::set(char *n, int i, int g) {
strcpy(name, n);
id = i; grade = g;
}
void StudentList::show() {
cout << "氏名:" << name;
cout << "\t学籍番号:" << id;
cout << "\t学年:" << grade << "\n";
}

int main() {
StudentList slist[10]; //入力用にオブジェクトの配列を宣言
int id, grd; char nm[50]; //入力用変数
int max = 3; //最大件数
StudentList *ptr; //配列の操作用にポインタ変数を宣言
ptr = slist; //ポインタ渡し,ここで配列とポインタを接続
for (int i=0; i<max ; i++ ) {
cout << i+1 << "人目のデータを入力します\n";
cout << "名前を入力してください:"; cin >> nm;
cout << "学籍番号を入力してください:"; cin >> id;
cout << "学年を入力してください:"; cin >> grd;
//仮の入力用変数からポインタの先頭にデータを格納し、ポインタを進行させる.
ptr->set(nm, id, grd); ptr++;
//※このptr++で配列1行分、ポインタが進む
}
ptr = slist; //ふたたびポインタをリセット
for (int i = 0; i < max; i++ ) {
cout << i+1 << "\t";
ptr->show(); //このような形でメソッドが呼べることに注意
ptr++;
}
return 0;
}
[/code]

実行すると、10人分の名前と学籍番号、学年の入力を強いられるだけのマゾプログラムです。
しかも最後の return 0; にブレイクポイントを仕込んでおかないと結果が一瞬で流れて消えます。
それではあまりにご無体ですので、ここではmax=3として端折っています。レポートではmax=3としたら誤りです。

ちなみに講義中はptrのことを『ハンドル』と呼んでしまいましたが、厳密には異なります。
ここは固定のメモリアドレスをptrに渡しているので『ポインタ』と呼ぶのが適切でしょう。
『ハンドル』とは、動的にメモリ配置が変わる場合、たとえばガーベージコレクションなどを備えたJavaやC#のような環境において、実メモリアドレスが移動しても、捕まえておけるオブジェクトのことを『ハンドル』と呼ぶべきようです。

つづいてQ2です。タイトルは「総合問題1」となっています。

先ほどのQ1の続きからはじめて、成績を管理するResultListクラスを追加します。
先述のStudentListクラスをPublicに継承して、公開メンバとして100個までの科目名を格納し、その単位異数と評価を格納します。また格納されている科目数を記憶する変数を非公開メンバ変数として持ちます。関数は評価を格納するための関数Regist()と、全科目の科目名、単位数、評価を出力するshowResult()を持ちます。

以下のようなクラス設計、継承(inheritance)の関係がイメージできましたでしょうか?

Classes
(Visual Studio 2010の「クラスダイアグラム」機能で描画してみました)

継承をコードにするとこんな感じになります。

[code lang=”cpp”]
class ResultList : public StudentList {
char course[100][50]; //科目名
int credit[100]; //単位数
char grade[100]; //評価
int number; //格納してある科目数
public:
ResultList() { number = 0; }
void regist(char *title, int crd, char grd);
void showResult();
};
[/code]

なお、今回のプログラムでは入力チェックなどは一切行いません。削除や変更もしませんし、科目名の重複もチェックしません。

[code lang=”cpp”]
//Q2:総合問題1 成績管理(入力)
#include <iostream>
#include <cstring>
using namespace std;
class StudentList {
char name[50];
int id, grade;
public:
void set(char *n, int i, int g);
void show();
};
void StudentList::set(char *n, int i, int g) {
strcpy(name, n);
id = i; grade = g;
}
void StudentList::show() {
cout << "氏名:" << name;
cout << "\t学籍番号:" << id;
cout << "\t学年:" << grade << "\n";
}
//ここから上はQ1と同じ
//ここから下はテキストにある通り、StudentListを継承したResultListを宣言
class ResultList : public StudentList {
char course[100][50]; //科目名
int credit[100]; //単位数
char grade[100]; //評価
int number; //格納してある科目数
public:
ResultList() { number = 0; }
void regist(char *title, int crd, char grd);
void showResult();
};
void ResultList::regist(char *title, int crd, char grd) {
strcpy(course[number], title);
credit[number] = crd;
grade[number] = grd;
number++;
}
void ResultList::showResult() {
//格納してある科目数すべてについてリストする
for (int i = 0; i < number; i++ ) {
cout << "科目名:" << course[i];
cout << "\t単位数:" << credit[i];
cout << "\t評価:" << grade[i] << "\n";
}
}

int main() {
ResultList rlist[10];
int i,n; char str[50]; char c;
//名前学籍学年データ , 継承したResultListの配列にセットします
rlist[0].set("高坂穂乃果",1123005, 3);
rlist[1].set("絢瀬絵里", 1023003, 4);
rlist[2].set("南ことり", 1123008, 3);
rlist[3].set("園田海未", 1123039, 3);
rlist[4].set("初音ミク", 1023010, 3);
rlist[5].set("ルカ", 1223007, 2);
rlist[6].set("リン", 1023007, 4);
rlist[7].set("レン", 1223008, 2);
rlist[8].set("かいと", 1023015, 4);
rlist[9].set("らぴす", 1323013, 1);

while (1) {
cout << "学生一覧\n";
for (i = 0; i < 10 ; i++ ) {
cout << i+1 << "\t";
rlist[i].show(); //普通はこう呼ぶほうが多いですよね。継承元のStudentList::show()です
}
cout << "何番の学生の成績を入れますか?\n";
cin >> i;
cout << "成績を入力してください\n入力終了はendを科目名に入れて下さい\n";
while(1) {
cout << "科目名:"; cin >> str;
if (strcmp(str, "end") == 0) break;
cout << "単位数:"; cin >> n;
cout << "評価:"; cin >> c;
rlist[i-1].regist(str, n, c );
}
rlist[i-1].show();
cout << "この学生のデータを入力しました。\n終了するなら1を続けるなら0を:";
cin >> n;
if (n == 1) break;
}
//結果表示
for (i = 0; i < 10; i++ ) { //個々の学生についてループ
rlist[i].show(); //個々の学生の情報について表示
rlist[i].showResult(); //個々の科目の成績について表示
cout << "\n";
}
return 0;
}
[/code]

【実行結果】
cpp0521q2

9番目の「かいと」(KAIT!?)と10番目の「らぴす」の成績を入力しています。
「応用プログラミングA」が同じ名前なのですが、見た目には動作しています、が、デバッガ仕掛けるとわかりますが、別の科目になっています。
重複チェックを入れるのはさほど難しいことではないので考察としてやってみてもよいのでは。
また結果を表示するshow()ももう一工夫してもいいように思います(Q3にもありますので…)。
それに「end」と入れずに[0]を入れると終わるなど、工夫のしようはありそうです。
cinとifを使ったコマンドプロンプトによる対話は、インタラクティブなプログラムの基本中の基本なので しれっと 書けるようになってください。

さて最後のQ3「総合問題2」です。

前述Q2のResultListクラスに総合成績評価をあらわすGPAを追加します。
GPAは成績評価のSを4、Aを3、Bを2、Cを1、それ以外を0とした取得講義の平均で求めます。
また先ほどのRegist()を拡張してすでに同盟の科目の成績が入力されている場合には評価を上書き修正するようにします。
さらに科目と成績を削除するdel()も実装します。

0521q3class

以下、サンプルソースです。
main()がないととっかかりがつかみづらいと思いますので。
★レポート締切前なので、ResultListクラスの個々のメソッド実装は未公開です。

[code lang=”cpp”]
//0521 課題3 総合問題2
#include <iostream>
#include <cstring>
using namespace std;

class StudentList {
char name[50];
int id;
int grade;
public:
void set(char *n, int i, int g);
void show();
};
void StudentList::set(char *n, int i, int g) {
strcpy(name, n);
id = i;
grade = g;
}
void StudentList::show() {
cout << "氏名:" << name;
cout << "\t学籍番号:" << id;
cout << "\t学年:" << grade << "\n";
}
class ResultList : public StudentList {
char course[100][50];
int credit[100];
char grade[100];
int number;
double gpa; //今回追加
public:
ResultList() { number = 0; gpa = 0; }
void regist(char *title, int crd, char grd);
void showResult();
void del(char *title);
double get_gpa() { return gpa; }
};

void ResultList::regist(char *title, int crd, char grd) {
int i, sumc = 0, sumg = 0;
for (i = 0; i < number; i++) {
if (strcmp(course[i], title) == 0) {
credit[i] = crd;
grade[i] = grd;
break;
}
}
if (i == number) {
strcpy(course[number], title);
credit[number] = crd;
grade[number] = grd;
number++;
}
for (i = 0; i < number; i++) {
sumc += credit[i];
switch (grade[i]) {
case ‘S’:
sumg += 4 * credit[i];
break;
case ‘A’:
sumg += 3 * credit[i];
break;
case ‘B’:
sumg += 2 * credit[i];
break;
case ‘C’:
sumg += 1 * credit[i];
break;
default:
break;
}
}
gpa = (double)sumg / sumc;
}

void ResultList::showResult() {
for (int i = 0; i < number; i++) {
cout << "科目名:" << course[i];
cout << "\t単位数:" << credit[i];
cout << "\t評価:" << grade[i] << "\n";
}
}

void ResultList::del(char *title) {
int i, j, sumc = 0, sumg = 0;
for (i = 0; i < number; i++) {
if (strcmp(course[i], title) == 0) {
// 以下は登録されている科目の順番を変えないように処理している.順番を変えてもよいならもっと簡単
for (j = i; j < number; j++) {
strcpy(course[j], course[j+1]);
credit[j] = credit[j+1];
grade[j] = grade[j+1];
}
number–;
for (j = 0; j < number; j++) {
sumc += credit[j];
switch (grade[j]) {
case ‘S’:
sumg += 4 * credit[j];
break;
case ‘A’:
sumg += 3 * credit[j];
break;
case ‘B’:
sumg += 2 * credit[j];
break;
case ‘C’:
sumg += 1 * credit[j];
break;
default:
break;
}
}
gpa = (double)sumg / sumc;
break;
}
}
}
//以下はmainの参考。
int main() {
ResultList rlist[10];
int i, j, n;
char str[50];
char c;
//学生ダミーデータ:レポートでそのまま使用した場合はカンニングとみなします :-p
rlist[0].set("高坂穂乃果", 1123005, 3);
rlist[1].set("絢瀬絵里", 1023003, 4);
rlist[2].set("南ことり", 1123008, 3);
rlist[3].set("園田海未", 1123039, 3);
rlist[4].set("星空凛", 1023010, 4);
rlist[5].set("西木野真姫", 1223014, 2);
rlist[6].set("東條希", 1023007, 4);
rlist[7].set("小泉花陽", 1223008, 2);
rlist[8].set("矢澤にこ", 1023015, 4);
rlist[9].set("アルパカ", 1323013, 1);
while (1) {
cout << "学生一覧\n";
for (i = 0; i < 10; i++) {
cout << i+1 << "\t";
rlist[i].show();
}
// 以下では入力値の検証を行っていない.本当は入力値の検証を行った方がよい
cout << "何番の学生のデータを処理しますか?";
cin >> i;
cout << "成績を入力するには1を、削除するには2を入力してください:";
cin >> j;
cout << "入力を終了するには科目名にendと入力してください。\n";
if (j == 1) {
while (1) {
cout << "科目名:"; cin >> str;
if (strcmp(str, "end") == 0) break;
cout << "単位数:"; cin >> n;
cout << "評価:"; cin >> c;
rlist[i-1].regist(str, n, c);
}
} else {
while (1) {
cout << "科目名:"; cin >> str;
if (strcmp(str, "end") == 0) break;
rlist[i-1].del(str);
}
}
rlist[i-1].show();
cout << "この学生のデータを入力しました。\n\n";
cout << "入力を終了しますか?\n";
cout << "終了するなら1を、続けるなら0を入力してください:";
cin >> n;
if (n == 1) break;
}
for (i = 0; i < 10; i++) {
rlist[i].show();
rlist[i].showResult();
cout << "GPA:" << rlist[i].get_gpa() << "\n\n";
}
return 0;
}
[/code]

実行結果のスクリーンショットはうまく、登録や削除を説明できるように複数撮りましょうね!
たとえば、このスクリーンショットだけでは何が何だかわかりませんよね?

0521q3

第7回に続きます。

C++のフレンド関数

2013/5/14の「応用プログラミングA(C++)」の講義ふりかえり.

Q1は,独習C++の3章までの復習として関数とオブジェクト.
クラスに属していないメイン関数を作って,先に現れているクラスCoordを引数や戻り値に指定している.

[code lang=”cpp”]
#include
#include
using namespace std;
//クラスCoordの宣言
class Coord {
double x,y,z;
public:
void set_x(double u) {x=u;}
void set_y(double v) {y=v;}
void set_z(double w) {z=w;}
double get_x() {return x;}
double get_y() {return y;}
double get_z() {return z;}
void Show();
};
void Coord::Show() {
cout << "(" << x << "," << y << "," << z << ")";
}

//Coordオブジェクトを返す、中点を求める関数
Coord mid_Coord(Coord ob1, Coord ob2);
//Coordオブジェクトを返す、距離を求める関数
double dist_Coord(Coord ob1, Coord ob2);

int main() {
Coord p1,p2,p3;
//p1,p2に3次元座標をセットしていく
p1.set_x(1.0f); p1.set_y(6.5f); p1.set_z(-10.0f);
p2.set_x(-1.0f); p2.set_y(1.5f); p2.set_z(4.0f);

cout << "点A"; p1.Show(); cout << endl;
cout << "点B"; p2.Show(); cout << endl;
//中点p3を取得
p3 = mid_Coord(p1,p2);
cout <<"ABの中点"; p3.Show(); cout << endl;
//距離を求める,値を返すだけなのでリダイレクトで出力できる
cout <<"AB間の距離" << dist_Coord(p1,p2) << endl;
return 0;
}
//中点を求める関数の実装
Coord mid_Coord(Coord ob1, Coord ob2) {
Coord ob;
ob.set_x( (ob1.get_x() + ob2.get_x()) / 2.0f );
ob.set_y( (ob1.get_y() + ob2.get_y()) / 2.0f );
ob.set_z( (ob1.get_z() + ob2.get_z()) / 2.0f );
return ob;
}
//距離を求める関数の実装,1行で実装してみる
double dist_Coord(Coord ob1, Coord ob2) {
return sqrt(
( ob2.get_x() – ob1.get_x() ) * ( ob2.get_x() – ob1.get_x() ) +
( ob2.get_y() – ob1.get_y() ) * ( ob2.get_y() – ob1.get_y() ) +
( ob2.get_z() – ob1.get_z() ) * ( ob2.get_z() – ob1.get_z() )
);
}
[/code]

Q2はQ1の復習に引き続き,「フレンド関数」を使った実装方法を学ぶ.
色名と色の値を扱うクラスCNameを引数として,円クラスCircleのオブジェクトに対して,「色が一致しているか?」を判定するisSame(CName col)を宣言・実装する必要が有るため friend を名乗る必要がある.

[code lang=”cpp”]
#include <iostream>
#include <cstring>
using namespace std;
class CName;//ここはクラス名だけ宣言してみた
class Circle {
double x,y,radius; int r,g,b;
public:
void set_xyr(double s, double t, double r) { x = s; y = t; radius = r; }
void set_color(int u, int v, int w) { r = u; g = v; b = w; }
void Show();
bool isSame(CName col);
};
class CName {
char name[50]; int r,g,b;
public:
CName (char* str, int u, int v, int w);
char* get_name() { return name; }
void Show();
friend bool Circle::isSame(CName col);
};
//friend関数isSameの実装
bool Circle::isSame(CName col) {
if (r == col.r && g == col.g && b == col.b ) {
return true;
} else {
return false;
}
}
//CName(色名,RGB値)のコンストラクタ
CName::CName(char* str, int u, int v, int w) {
strcpy(name, str);
r = u; g = v; b = w;
}
void CName::Show() {
cout << name << ":(" << r << "," << g << "," << b << ")\n";
}

int main() {
Circle c;
CName co1("Red",255,0,0); CName co2("Green",0,255,0); CName co3("Blue",0,0,255);
c.set_xyr(2.0f,3.0f,5.0f);
c.set_color(255,0,0); //赤
cout << "円の情報を表示\n"; c.Show();
cout << "色1の情報を表示\n"; co1.Show();
cout << "色2の情報を表示\n"; co2.Show();
cout << "色3の情報を表示\n"; co3.Show();
cout << "この円の色は" << co1.get_name();
if (c.isSame(co1)) {
cout << "です" << endl;
} else {
cout << "ではありません" << endl;
}
cout << "この円の色は" << co2.get_name();
if (c.isSame(co2)) {
cout << "です" << endl;
} else {
cout << "ではありません" << endl;
}
cout << "この円の色は" << co3.get_name();
if (c.isSame(co3)) {
cout << "です" << endl;
} else {
cout << "ではありません" << endl;
}

return 0;
}
//void Show()の実装
void Circle::Show() {
cout << "座標("<< x << ","<< y <<") 半径=" << radius << endl;
cout << "RGB=("<< r <<","<< g <<","<< b << ")" << endl;
}
[/code]

Q3はQ2の配列による拡張.

まだ課題提出締め切り前なので,main文以下だけ掲示しておきます.→全文掲載しました

[code lang=”cpp”]
#include
#include
using namespace std;

class CName;

class Circle {
double x, y;
double radius;
int r, g, b;
public:
void set_xyr(double s, double t, double r) {
x = s;
y = t;
radius = r;
}
void set_color(int u, int v, int w) {
r = u;
g = v;
b = w;
}
void show();
bool isSame(CName col);
};

class CName {
char name[50];
int r, g, b;
public:
CName(char* str, int u, int v, int w);
char* get_name() {
return name;
}
void show();
friend bool Circle::isSame(CName col);
};

void Circle::show() {
cout << "座標:(" << x << "," << y << ")\n";
cout << "半径:" << radius << "\n";
cout << "RGB:(" << r << "," << g << "," << b << ")\n";
}

bool Circle::isSame(CName col) {
if (r == col.r && g == col.g && b == col.b)
return true;
else
return false;
}

CName::CName(char* str, int u, int v, int w) {
strcpy(name, str);
r = u;
g = v;
b = w;
}

void CName::show() {
cout << name << ":(" << r << "," << g << "," << b << ")\n";
}

int main() {
Circle ob[3];
CName co[8] = { CName("White", 255, 255, 255),
CName("Black", 0, 0, 0),
CName("Red", 255, 0, 0),
CName("Green", 0, 255, 0),
CName("Blue", 0, 0, 255),
CName("Cyan", 0, 255, 255),
CName("Magenta", 255, 0, 255),
CName("Yellow", 255, 255, 0) };
int i, j, flag;

ob[0].set_xyr(2.0, 3.0, 5.0);
ob[0].set_color(255, 0, 0);
ob[1].set_xyr(4.0, 5.0, 6.5);
ob[1].set_color(0, 255, 0);
ob[2].set_xyr(1.5, 1.5, 2.0);
ob[2].set_color(150, 150, 150);

for (i = 0; i < 3; i++) {
cout << "円" << i+1 << "の情報を表示\n";
ob[i].show();
}

cout << "\n登録してある色一覧\n";
for (i = 0; i < 8; i++) {
co[i].show();
}
cout << "\n";

for (i = 0; i < 3; i++){
flag = 0;
for (j = 0; j < 5; j++) {
if (ob[i].isSame(co[j])) {
cout << "円" << i+1 << "の色は" << co[j].get_name() << "です\n";
flag = 1;
break;
}
}
if (!flag) {
cout << "円" << i+1 << "の色は登録されている色にありません\n";
}
}

return 0;
}
[/code]

【実行結果】

半径:5
GB:(255,0,0)
円2の情報を表示
座標:(4,5)
半径:6.5
GB:(0,255,0)
円3の情報を表示
座標:(1.5,1.5)
半径:2
GB:(150,150,150)

登録してある色一覧
hite:(255,255,255)
lack:(0,0,0)
ed:(255,0,0)
reen:(0,255,0)
lue:(0,0,255)
yan:(0,255,255)
agenta:(255,0,255)
ellow:(255,255,0)

円1の色はRedです
円2の色はGreenです
円3の色は登録されている色にありません

次回は「C++でのポインタと配列の利用」です。