掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.30111

C++ですが、共用体のメンバがクラス型でそのクラスのメンバを参照する方法が知りたいのです。
投稿者---Aoi@Toukai(2007/05/11 01:49:54)


ゼミでデータベースを扱うプログラムを作ることになったのですが、わからないところがありまして、是非皆様の知恵を拝借したいです。
   
あるデータベースに複数行、文字や数値が書いてあります。
1,1999,11,neko,2,brown,tama
2,2000,3,inu,ote,3.5,maruchiz
…以降続く(実際のデータは項目数が十数個で数千行あるみたいです)

これらのデータを一行ずつ読み込んで、データの値を配列Dataに
格納できたとします。オブジェクトを宣言して、配列の値を
適切なメンバ変数に格納します。これを繰り返します。
はじめの4つの変数はどの行でも共通の既知の型、5番目以降の型や文字の個数はまちまちとします。
下記のようにクラスを作ります。
Animalクラスのメンバにデータのはじめ4つの変数を、
5番目以降は(例えば4番目で判別して)Catクラスのメンバー変数あるいは
Dogクラスのメンバ変数に格納します。この2つのクラスはAnimalクラスを
継承します。MyPetクラスではメンバ変数に共用体をもちます。
共用体のメンバはCat、Dogクラスです。
(ただし、コンストラクタ、デストラクタ、メンバ関数、シリアライズなどは割愛)

Mypet.cppにてMypetクラスのオブジェクト(ポインタ)を作成して、各メンバを参照する方法が知りたいです。共用体のメンバであるクラス、派生クラスを介して基クラスのメンバを指定する記述方法がわかりません。

「オブジェクト.メンバ」や
「オブジェクト(ポインタ)->メンバ」はわかるのですが、他クラスのメンバへのアクセス、共用体を介したときとなると途端にどう考えていいかわかりません。

<pre>class Mypet  // Mypet.h
{
   public:
       union sky{
           Cat* c_object;
           Dog* d_object;          
       };
};

// Cat.h
class Cat: public Animal
{
   public:
      int c_age;
      int c_color;      
      CString c_name;
};

// Dog.h
class Dog: public Animal
{
   public:
      CString d_skill;
      int d_weight;      
      CString d_kind;
};

// Animal.h
class Animal
{
   public: //あえて
     int id;
     int year;
     int month;
     CString name;  
};

</pre>

OSはWindowsXPでVisualC++2005を使っています。共用体内の宣言のところもいまひとつわかりません。*がないと、コピーコンストラクタができるとエラーが出たりしました。宜しくお願いします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:C++ですが、共用体のメンバがクラス型でそのクラスのメンバを参照する方法が知りたいのです。 30112 επιστημη 2007/05/11 06:12:45


No.30112

Re:C++ですが、共用体のメンバがクラス型でそのクラスのメンバを参照する方法が知りたいのです。
投稿者---επιστημη(2007/05/11 06:12:45)
http://blogs.wankuma.com/episteme/


class Animal{};
class Cat : public Animal {};
class Dog : public Animal {};
class Mypet { public: Animal* object; };

Mypet x, y;
x.object = new Cat();
y.object = new Dog();

で十分ではないかと。




この投稿にコメントする

削除パスワード

No.30120

Re:C++ですが、共用体のメンバがクラス型でそのクラスのメンバを参照する方法が知りたいのです。
投稿者---Aoi@Toukai(2007/05/12 15:04:50)


επιστημηさん、ご回答ありがとうございます。
 
確かに今回の例ではそれで対応できそうな気はします。
まだつくっていないのですけど。
ただ、気になるので今後のために教えてほしいです。
共用体を介したときの書き方はどうすればいいのでしょう?
考え方が知りたいです。基礎の本では載っていない内容ですので。
よろしくお願いします。 


この投稿にコメントする

削除パスワード

No.30126

Re:C++ですが、共用体のメンバがクラス型でそのクラスのメンバを参照する方法が知りたいのです。
投稿者---yoh2(2007/05/13 01:38:19)


# 簡単にまとめるつもりが長文に……

なぜそこまで共用体にこだわるのでしょうか?

- ベースクラスBと、Bの派生クラスD1, D2がある。
- 利用者は、D1とD2のインスタンスを同じ変数に代入して使いたい。

というパターンなら、επιστημηさんの回答通り、Bへのポインタを用意して、
そこにD1やD2のインスタンスへのポインタを代入するだけです。そこに共用体の出番は
ありません。
ちなみに、C++に限らず、オブジェクト指向とされる言語は大抵(私の知っている限りすべて)
このようなことが可能です。
できなければオブジェクト指向の大事な概念のひとつ、継承の魅力が半減どころでは済みませんから。

同じ変数に代入した上で、それぞれのクラス独自の挙動も望むというなら、仮想関数を
用意すれば事足りる場合がほとんどです。

(あまりよい設計とは言えませんが)D1やD2固有のメンバにアクセスしたいなど、
どうしてもD1*やD2*がほしい場合はB*をstatic_castやdynamic_cast(どちらを
使うべきかはケースバイケース)を使えばよいです。この場合も共用体の出番はありません。

一応、無理矢理共用体を用いた場合とベースクラスのポインタを用いた場合のコードを並べてみます。
共用体を使うとやたら煩雑になるのが分かるかと。

ここで、共用体を用いたパターンでは、
    union U{
        D1 *d1;
        D2 * d2;
    };
    U *u;
という宣言がなされ(実際は、後述の型判別を行うために、さらにもう一段クラスで
囲む必要があるでしょう)、B*を用いたパターンでは
    B *b;
という宣言がなされているものとします。

その1: Bのメンバmbにアクセス
1-1. 共用体を用いたパターン
    if(uに格納されているインスタンスはD1型){
        ... u->d1->mb ...
    }
    else{ // uに格納されているインスタンスはD2型
        ... u->d2->mb ...
    }

1-2. B*を用いたパターン
   ... b->mb ...

その2: インスタンスがD1型かどうかの判定
2-1. 共用体を用いたパターン
    if(何か独自の方法){
        ...
    }

2-2. B*を用いたパターン (ただし、Bに最低ひとつの仮想関数が定義されている必要あり)
    // 方法その1
    if(typeid(*b) == typeid(D1)){
        ...
    }

    // 方法その2
    if(dynamic_cast<D1 *>(b) != NULL){
        ...
    }

3-1. D1固有のメンバmd1にアクセス (実際の型がD1であることは保証されているものとする)
共用体を用いたパターン
    ... u->d1->md1 ...

3-2. B*を用いたパターン
    ... dynamic_cast<D1 *>(b)->md1 ... // 場合によってはstatic_cast

1-1で、共通のメンバにアクセスするのにも一々型を判定してやらなければならないのが
共用体を使う場合に最も不便なところ。どうせメンバは共通なのだから、u->d1かu->d2の
どちらか一方を通じてアクセスすればいいじゃないかと思われるかもしれませんが、
たとえベースクラスの共通メンバにアクセスする場合でも、D1のインスタンスをD2型への
ポインタを通じて利用することは規格上NGです。

3が唯一共用体の方が簡単に見える例ですが、このコード以前に、何か独自の方法で型を
判定する(2参照)必要があることを考えると、本当に簡単かどうかは疑問です。


この投稿にコメントする

削除パスワード

No.30131

Re:C++ですが、共用体のメンバがクラス型でそのクラスのメンバを参照する方法が知りたいのです。
投稿者---επιστημη(2007/05/13 23:30:14)
http://blogs.wankuma.com/episteme/


#include <iostream>
#include <string>

using namespace std;


enum pet_kind { cat, dog };

class Animal {
  string name_;
public:
  Animal(string n) : name_(n) {}
  string name() const { return name_; }
};

class Cat : public Animal {
public:
  Cat(string n) : Animal(n) {}
  void nyan() const { cout << name() << " にゃん\n"; }
};

class Dog : public Animal {
public:
  Dog(string n) : Animal(n) {}
  void wan() const { cout << name() << " わん\n"; }
};

class Mypet {
public:
  union {
    Cat* c_object;
    Dog* d_object;          
  };
  pet_kind kind;
};

int main() {
  Mypet pet[2];
  pet[0].c_object = new Cat("タマ"); pet[0].kind = cat;
  pet[1].d_object = new Dog("ポチ"); pet[1].kind = dog;
  for ( int i = 0; i < 2; ++i ) {
    switch ( pet[i].kind ) {
    case  cat: pet[i].c_object->nyan(); break;
    case  dog: pet[i].d_object->wan();  break;
    default: break;
    }
  }
}




この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧