ホーム » スタッフ (ページ 123)

スタッフ」カテゴリーアーカイブ

2025年6月
1234567
891011121314
15161718192021
22232425262728
2930  

検索・リンク

Windows Update未適用が…

先週末の土日と、Kinectを使ったIT研向けの講習会を 3F演習室で行ったた。 この際に、Visual Studio をインストールする必要があって、 作業をしていたが、Windows Update の未適用が大量にあり、 実質2日間かけてアップデートを行った。

FEREC利用で最初の未適用…

原因は、WiFi設定で FEREC を使うようになっていると、 学生がWiFiで接続している時だけネットワークに繋がるため、 その作業時以外は、ネットワークにつながらず Update 未適用 になるのが一因とも思われる。

Windows Updateサーバが遮断された

最近は、有線LANでの接続状態にしてあるが、WiFiでUpdate 未適用の頃に、Microsoftのupdate用サーバ情報が更新されず、 Updateサーバを偽物と誤認し、ファイアウォールが接続の邪魔を して Windows Update が動かなかったと思われる。

一旦、ファイアウォールを止めて更新をかけたりしたら、 無事に更新がかかるようになった。 でも、100件以上の更新で、Updateの適用待ちやら再起動やらで、 実質2日仕事であった。

仮想関数と純粋仮想基底クラス

前々回の講義では派生と継承の説明にて、次のようなプログラムを説明した。

派生と継承の復習

// 基底クラス
class Person {
private:
   char name[ 20 ] ;
   int  age ;
public:
   Person( const char* s , int a ) {
      strcpy( name , s ) ;
      age = a ;
   }
   void print() {
      printf( "%s %d\n" , name , age ) ;
   }
} ;
// 派生クラス
class Student : public Person {
private:
   char dep[ 10 ] ;
   int  grade ;
public:
   Student( const char* s , int a , const char* d , int g )
     : Person( s , a )
   {
      strcpy( dep , d ) ;
      grade = g ;
   }
   void print() { // 継承でなくStudent版のprintを定義
      Person::print() ;
      printf( "= %s %d\n" , dep , grade ) ;
   }
} ;
int main() {
   // 派生と継承の確認
   Person tsaitoh( "tsaitoh" , 50 ) ;
   tsaitoh.print() ;
   Student naka( "naka" , 22 , "PS" , 2 ) ;
   naka.print() ; // Student版を実行
   // 異なる型のデータをごちゃ混ぜにできないか?
   Person* table[2] ;
   table[0] = &tsaitoh ;
   table[1] = &naka ;
   for( int i = 0 ; i < 2 ; i++ ) {
      table[i]->print() ;
   }
   return 0 ;
}

このプログラムのmain() では、tsaitohとnakaのデータを 表示させているが、tsaitohとnakaは、オマケの有る無しの違いはあっても、 元をたどれば、Person型。ごちゃまぜにできないだろうか?

int main() {
   :
   // 異なる型のデータをごちゃ混ぜにできないか?
   Person* table[2] ;
   table[0] = &tsaitoh ;
   table[1] = &naka ;
   for( int i = 0 ; i < 2 ; i++ ) {
      table[i]->print() ;
   }
   return 0 ;
}

C++では、派生クラスは格下げして基底クラスのように振る舞うこともできる。 上記の例では、Studentのポインタ型である、&nakaは、 Personのポインタ型として振る舞うこともできる。

ただし、table[]に格納する時点で、Person型へのポインタなので、 table[i]->print() を呼び出しても、Personとして振る舞うため、 tsaitoh 50 / naka 22 が表示される。

仮想関数

上記のプログラムでは、Student型には、名前,年齢,所属,学年をすべて表示する Student::print() が宣言してある。 であれば、「naka 22」 ではなく、「naka 22 PS 2」と表示したくはならないか?

上記の例では、table[] に格納する段階で、格下げされているため、「naka 22」しか表示できない。 しかし、以下のように書き換えると、「naka 22 PS 2」と表示できる。

// 基底クラス
class Person {
private:
   char name[ 20 ] ;
   int  age ;
public:
   Person( const char* s , int a ) {
      strcpy( name , s ) ;
      age = a ;
   }
   virtual void print() {
      printf( "%s %d\n" , name , age ) ;
   }
} ;
// 派生クラス
class Student : public Person {
private:
   char dep[ 10 ] ;
   int  grade ;
public:
   Student( const char* s , int a , const char* d , int g )
     : Person( s , a )
   {
      strcpy( dep , d ) ;
      grade = g ;
   }
   virtual void print() { // 継承でなくStudent版のprintを定義
      Person::print() ;
      printf( "= %s %d\n" , dep , grade ) ;
   }
} ;
int main() {
   Person tsaitoh( "tsaitoh" , 50 ) ;
   Student naka( "naka" , 22 , "PS" , 2 ) ;
   // 異なる型のデータをごちゃ混ぜにできないか?
   Person* table[2] ;
   table[0] = &tsaitoh ;
   table[1] = &naka ;
   for( int i = 0 ; i < 2 ; i++ ) {
      table[i]->print() ;
   }
   return 0 ;
}

上記の例の用に、printメソッドに virtual 宣言を追加すると、 C++では、tsaitoh,naka のデータ宣言時に、データ種別情報が埋め込まれる。 この状態で、table[i]->print() を呼び出されると、 データ種別毎のprint()を呼び出してくれる。 (この実装では、前回授業の関数ポインタが使われている)

ここで、学生さんから、「table[] の宣言をStudentで書いたらどうなるの?」という 質問がでた。おもわず『良い質問ですねぇ〜』と池上彰ばりの返答をしてしまった。

Student* table[] ;
table[0] = &tsaitoh ; // 文法エラー
// 派生クラスは基底クラスにはなれるけど、
// 基底クラスが派生クラスになることはできない。
table[1] = &naka ;

純粋仮想基底クラス

// 純粋仮想基底クラス
class Object {
public:
   virtual void print() = 0 ; // 中身の無い純粋基底クラスを記述しない時の書き方。
} ;
// 整数データの派生クラス
class IntObject : public Object {
private:
   int data ;
public:
   IntObject( int x ) {
      data = x ;
   }
   virtual void print() {
      printf( "%d\n" , data ) ;
   }
} ;
// 文字列の派生クラス
class StringObject : public Object {
private:
   char data[ 100 ] ;
public:
   StringObject( const char* s ) {
      strcpy( data , s ) ;
   }
   virtual void print() {
      printf( "%s\n" , data ) ;
   }
} ;
// 実数の派生クラス
class DoubleObject : public Object {
private:
   double data ;
public:
   DoubleObject( double x ) {
      data = x ;
   }
   virtual void print() {
      printf( "%lf\n" , data ) ;
   }
} ;
// 動作確認
int main() {
   Object* data[3] = {
      new IntObject( 123 ) ,
      new StringObject( "abc" ) ,
      new DoubleObject( 1.23 ) ,
   } ;
   for( int i = 0 ; i < 3 ; i++ ) {
      data[i]->print() ;
   }
   return 0 ;
} ;

この書き方では、data[]には、整数、文字列、実数という異なるデータが入っているが、 Objectという純粋仮想基底クラスを通して、共通な型のように扱えるようになる。 そして、data[i]->print() では、各型の仮想関数が呼び出されるため、 「123 abc 1.23」 が表示される。

ここで、Object の様な一見すると中身が何もないクラスを宣言し、 このクラスから様々な派生クラスを用いるプログラムテクニックは、 広く利用され、Objectのような基底クラスは、純粋仮想基底クラスなどと呼ばれる。

関数ポインタと仮想関数への導入

派生と継承の基本の説明をしてきたので、次に説明する予定の仮想関数の導入として、 実装のために使われている関数ポインタを紹介。

関数ポインタ

関数ポインタとは、関数へのポインタであり、ポインタを変更することで、 処理を切り替えるために使われる。 まずは、動作説明の簡単なプログラムを紹介。

int add( int x , int y ) { // 加算関数
return x + y ;
}
int mul( int x , int y ) { // 乗算関数
return x * y ;
}
void main() {
int (*f)(int,int) ; // int×2引数、返り値intの関数へのポインタ
f = add ;
printf( "%d" , (*f)( 2 , 3 ) ) ; // 5を表示
f = mul ;
printf( "%d" , (*f)( 2 , 3 ) ) ; // 6を表示
}

関数ポインタを利用すれば、異なるデータに対する処理を、 汎用性高く作ることも可能となる。 例えば以下の vmax() 関数は、自分で用意した大小を比較するだけの関数を渡し、 それ以外の最大値を求めるための処理を行う。 このため、他のデータの最大値を求めたい場合でも、最大値を求める処理を すべて記載するのではなく、対象データの比較関数だけを記述すれば良い。

int intcmp( int* x , int* y ) { // 整数比較関数
if ( *x > *y )
return 1 ;
else if ( *x < *y )
return -1 ;
else
return 0 ;
}
int vmax( void* array ,    // 配列先頭アドレス
int size ,       // 配列データ件数
int sizeofdata , // 1件あたりのbyte数
int(*f)( void*,void* ) ) { // 比較関数
int i , max = 0 ;
for( i = 0 ; i < size ; i++ )
if ( (*f)( array + max * sizeofdata ,
array + i   * sizeofdata ) )
max = i ;
return max ;
}
int idata[ 4 ] = { 11 , 33 , 22 , 44 } ;
char sdata[ 4 ][ 4 ] = { "ab" , "bc" , "aa" , "c" } ;
void main() {
int m ;
// intcmp関数を使って、idata から最大値を探す
m = vmax( idata , 4 , sizeof(int) , intcmp ) ;
printf( "%d" , idata[ m ] ) ;
// strcmp関数を使って、sdata から最大値を探す
m = vmax( sdata , 4 , sizeof(sdata[0]) , strcmp ) ;
printf( "%s" , sdata[ m ] ) ;
}

2015年5月31日(第425回)

収録でお送りしました。

  • まるトレ傑作選 第89便 「アホ・バカ分布図(前編)」(平成27年2月1日放送)
  • 新入生の自己紹介
  • 新入生への質問攻め
  • 山田君からの勉強アドバイス

担当:小藤(2B、MIX)、山田(2B・MIX)、植村(2E)、鷲田(1EI)、西島(1E)、西(教員)

6/1よりOffice365ProPlusが使えます

高専機構とMicrosoft社との包括協定ですが、この6/1より本校学生の方は、 Office365 ProPlus が使えます。

Office 365 を使うと、 (1)メールやグループウェアとしての機能と、 (2)パソコンなどにアプリを入れることでWord,Excel,PowerPointなどが 使えるようになります。 今までは、Microsoftとの包括協定で売店でOSやOfficeのメディアを 安く購入し、学生さんの自宅パソコンにインストールが可能でした。 しかし、今後はこのOffice365によって、利用することになります。

Office365のアプリは、パソコン以外にも、iOSやAndroidのタブレット,スマート フォンでも提供されています。 Office365 ProPlus では、パソコン5台,タブレット5台,スマホ5台合計15台にイ ンストールできます。 データは、ユーザ認証のもとでOneDriveなどの機能を経由しながら、同期されます。

使い方

Office 365 をブラウザ上で使うには、https://portal.office.com/Home にアクセスし、 高専機構全体でのメールアドレスでloginします。 福井高専の方は、総合情報処理センターで利用するユーザIDの後ろに、"@fukui.kosen-ac.jp"をつけたものが、 Office365のメールアドレスになります。パスワードは、センターの端末と同じものを使ってください。

  login: xxxxxxxx@fukui.kosen-ac.jp
  password: センターと同じ
1505271953_806x538.png

ブラウザ上では、以下のような機能が利用できます。

1505271953_873x359.png

先に示した、"xxxxxxxx@fukui.kousen-ac.jp" は、そのままメールアドレスとしても使えます。 左上のメニューボタンを押すと表示されるものの、「メール」を使うと以下のような画面になります。

1505271953_997x371.png

パソコンにOffice365のインストール

高専機構でOffice365では、ブラウザ上だけでなくパソコンにOfficeをインストールして使うこともできます。
自宅の自分のパソコンで、前述の手順によりブラウザでログインすると、直後に以下の様な画面が表示されます。 この状態で「今すぐインストール」をクリックして下さい。

2015-06-29-Office365-install.png

ブラウザ上のOffice365の機能を使っている状態では、ブラウザの画面上部の「アカウント」→「Office365の設定」→「ソフトウェア」 でインストール画面を出してください。

ここで、インストールを選ぶと、画面下に「Setup…..exe(xxxxMB)を実行または保存しますか?」と表示が出てくるので、「実行(R)」を選んでください。 Windowsであれば、「次のプログラムにこのコンピュータへの変更を許可しますか?」などの表示が出てきます。 あとは「はい(Y)」を選べばインストールが行われます。

2015-06-29-Office365-install-final.png

派生と継承

隠ぺい化の次のステップとして、派生・継承を説明する。

派生を使わずに書くと…

元となるデータ構造(例えばPersonが名前と年齢)でプログラムを作っていて、 途中でその特殊パターンとして、所属と学年を加えた学生(Student)という データ構造を作るとする。

// 元となる構造体(Person)                                                                                                                                                  struct Person {
   char name[ 20 ] ; // 名前
   int  age ;        // 年齢
} ;
// 初期化関数
void set_Person( struct Person* p ,
                 char s[] , int x ) {
   strcpy( p->name , s ) ;
   p->age = x ;
}
// 表示関数
void print_Person( struct Person* p ) {
   printf( "%s %d\n" , p->name , p->age ) ;
}
void main() {
   struct Person saitoh ;
   set_Person( &saitoh , "t-saitoh" , 50 ) ;
   print_Person( &saitoh ) ;
}

パターン1(そのまんま…)

上記のPersonに、所属と学年を加えるのであれば、以下の方法がある。 しかし以下パターン1は、要素名がname,ageという共通な部分があるようにみえるが、 プログラム上は、PersonとPersonStudent1は、まるっきり関係のない別の型にすぎない。

このため、元データと共通部分があっても、同じ処理を改めて書き直しになる。

// 元のデータに追加要素(パターン1)
struct PersonStudent1 {
   char name[ 20 ] ; // 名前
   int  age ;        // 年齢
   char dep[ 20 ] ;  // 所属
   int  grade ;      // 学年
} ;
void set_PersonStudent1( struct PersonStudent1* p ,
                         char s[] , int x ,
                         char d[] , int g ) {
   strcpy( p->name , s ) ; // 同じことを書いてる
   p->age = x ;
   strcpy( p->dep , d ) ;  // 追加分はしかたない
   p->grade = g ;
}
// 名前と年齢だけ表示
void print_PersonStudent1( struct PersonStudent1* p ) {
   // また同じ処理を書いてる
   printf( "%s %d\n" , p->name , p->age ) ;
}
void main() {
   struct PersonStudent1 naka1 ;
   set_PersonStudent1( &naka1 ,
   "naka" , 22 , "PS" , 2 ) ;
   print_PersonStudent1( &naka1 ) ;
}

パターン2(元データの処理を少し使って…)

パターン1では、同じような処理を何度も書くことになり、面倒なので、 元データ用の関数をうまく使うように書いてみる。

// 元のデータに追加要素(パターン2)
struct PersonStudent2 {
   struct Person person ;
   char          dep[ 20 ] ;
   int           grade ;
} ;
void set_PersonStudent2( struct PersonStudent2* p ,
                         char s[] , int x ,
                         char d[] , int g ) {
   // Personの関数を部分的に使う
   set_Person( &(p->person) , s , x ) ;
   // 追加分はしかたない
   strcpy( p->dep , d ) ;
   p->grade = g ;
}
void print_PersonStudent2( struct PersonStudent2* p ) {
   // Personの関数を使う。
   print_Person( &p->person ) ;
}
void main() {
   struct PersonStudent2 naka2 ;
   set_PersonStudent2( &naka2 ,
   "naka" , 22 , "PS" , 2 ) ;
   print_PersonStudent2( &naka2 ) ;
}

このパターン2であれば、元データ Person の処理をうまく使っているので、 プログラムの記述量を減らすことはできるようになった。

しかし、print_PersonStudent2() のような処理は、元データ構造が同じなのに、 いちいちプログラムを記述するのは面倒ではないか?

そこで、元データの処理を拡張し、処理の流用ができないであろうか?

基底クラスから派生クラスを作る

オブジェクト指向では、元データ(基底クラス)に新たな要素を加えたクラス(派生クラス)を 作ることを「派生」と呼ぶ。派生クラスを定義するときは、クラス名の後ろに、 「:」「public/protected/private」基底クラス名を書く。

// 基底クラス
class Person {
private:
   char name[ 20 ] ;
   int  age ;
public:
   Person( const char s[] , int x ) {
      strcpy( name , s ) ;
      age = x ;
   }
   void print() {
      printf( "%s %d\n" , name , age ) ;
   }
} ;
// 派生クラス
class Student : public Person {
private:
   char dep[ 20 ] ;
   int  grade ;
public:
   Student( const char s[] , int x ,
            const char d[] , int g )
            : Person( s , x ) // 基底クラスのコンストラクタ
   {
      strcpy( dep , d ) ;
      grade = g ;
   }
} ;
void main() {
   Person saitoh( "t-saitoh" , 50 ) ;
   saitoh.print() ;
   Student naka( "naka" , 22 , "PS" , 2 ) ;
   naka.print() ;
}

ここで注目すべき点は、main()の中で、Studentクラス"naka"に対し、naka.print() を呼び出しているが、パターン2であれば、print_PersonStudent2()に相当するプログラムを 記述していない。 しかし、この派生を使うと Person の print() が自動的に流用することができる。 これは、基底クラスのメソッドを「継承」しているから、 このように書け、名前と年齢「naka 22」が表示される。

さらに、Student の中に、以下のような Student 専用の新しい print()を記述してもよい。

class Student ...略... {
   ...略...
   void print() {
      Person::print() ;
      printf( "%s %d\n" , dep , grade ) ;
   }
} ;
void main() {
   ...略...
   Student naka( "naka" , 22 , "PS" , 2 ) ;
   naka.print() ;
}

この場合は、継承ではなく機能が上書き(オーバーライト)されるので、 「naka 22 / PS 2」が表示される。

派生クラスを作る際の後ろに記述した、public は、他にも protected , private を 記述できる。

public    だれもがアクセス可能。
protected であれば、派生クラスからアクセスが可能。
派生クラスであれば、通常は protected で使うのが一般的。
private   派生クラスでもアクセス不可。

2015年5月24日(第424回)

収録でお送りしました。

  • まるトレ傑作選 第68便「タイトル(中編)」(平成26年8月24日放送)
  • 新入生の自己紹介
  • 新入生への質問攻め

担当:松島(4C)、稲葉(2EI・MC)、山田(2B・MIX)、木下(2EI)、水島(1C)、西(教員)

2015年5月17日(第423回)

  • まるトレ傑作選 第32便「主語(前編)」(平成25年11月24日放送)
  • 専門教科について
  • レポートの書き方について
  • 放送メディア研究会の年間活動計画について

担当:松島(4C・MC)、植村(2E・MIX)、川﨑(2EI)、西(教員)

2015年5月10日(第422回)

  • まるトレ傑作選 第16便「新幹線の名前」(平成25年7月26日放送)
  • キャンパスウォークについて
  • 体育祭の応援の話
  • 母の日について

担当:松島(4C・MIX)、田嶋(3C)、川﨑(2EI・MC)、西(教員)

2015年5月3日(第421回)

つつじ祭り会場の西山公園のたんなんFM特設スタジオから生放送!!

  • まるよし Train Pops ~ 国語と遊ぼう!  グランドフィナーレ
    • まるとれの定期運行は最終日となりました。これまでのご愛顧、ありがとうございました。新しいコーナーを企画中です。それまでは、「まるとれ傑作選」をお送りします。
  • 体育祭の結果について
  • キャンパスウォークについて

ゲスト:電子情報工学科卒業生 前田様

担当:田嶋(3C・MIX)、川﨑(2EI・MC)、中村(教員)、西(教員)

システム

最新の投稿(電子情報)

アーカイブ

カテゴリー