クラスメンバ変数アクセスについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
各務
記事: 5
登録日時: 9年前

クラスメンバ変数アクセスについて

#1

投稿記事 by 各務 » 9年前

こんばんわ。はじめて質問させていただきます。
クラス内変数にアクセスをしたいのですが、アドバイスを頂きたいです。

コード:

_declspec(align(16)) struct Float4
{
    float x, y, z, w;
};

class Vector4
{
public:
    Vector4(float x, float y, float z, float w)
    {
        f.x = x;
        f.y = y;
        f.z = z;
        f.w = w;
    }

    float& operator [] (unsigned int i)
    {
        return (&f.x)[i];
    }
    float operator [] (unsigned int i) const
    {
        return (&f.x)[i];
    }

private:
    Float4 f;
};

using std::cout;
using std::endl;

void Print(const Vector4& v)
{
    cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << endl;
}

void main()
{
    Vector4 v = {0.0f, 1.0f, 2.0f, 3.0f};
    Print(v);
    v[0] = 20.0f;
    Print(v);
    std::cin.get();
}

メンバ変数のFloat4のそれぞれの値にアクセスしたいです。

とりあえず考えていることは
1, ゲッタセッタ関数を作らない(propertyも含みます)
2, メンバ変数をpubicで持たない
です。

この方法以外にいい方法があればアドバイスお願いします。
またこの方法でも安全性は大丈夫でしょうか?自分で試したところ、値についてはちゃんと取得や設定などできていました。

よろしくお願いします。

環境 : Windows, VC2013

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: クラスメンバ変数アクセスについて

#2

投稿記事 by h2so5 » 9年前

自分だったらx, y, z, wはpublicにします。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: クラスメンバ変数アクセスについて

#3

投稿記事 by みけCAT » 9年前

各務 さんが書きました:この方法以外にいい方法があればアドバイスお願いします。
とりあえず、ぱっと思いつく方法を。

コード:

#include <iostream>
#define _declspec(a)

_declspec(align(16)) struct Float4
{
    float x, y, z, w;
};

class Vector4
{
    public:
        Vector4(float x, float y, float z, float w)
        {
            f.x = x;
            f.y = y;
            f.z = z;
            f.w = w;
        }

        float& operator [] (unsigned int i)
        {
            static float dummy = 0.0f;
            switch(i)
            {
                case 0: return f.x;
                case 1: return f.y;
                case 2: return f.z;
                case 3: return f.w;
                default: return dummy;
            }
        }
        float operator [] (unsigned int i) const
        {
            switch(i)
            {
                case 0: return f.x;
                case 1: return f.y;
                case 2: return f.z;
                case 3: return f.w;
                default: return 0.0f;
            }
        }

    private:
        Float4 f;
};

using std::cout;
using std::endl;

void Print(const Vector4& v)
{
    cout << v[0] << ' ' << v[1] << ' ' << v[2] << ' ' << v[3] << endl;
}

int main()
{
    Vector4 v = {0.0f, 1.0f, 2.0f, 3.0f};
    Print(v);
    v[0] = 20.0f;
    Print(v);
    std::cin.get();
}
各務 さんが書きました:またこの方法でも安全性は大丈夫でしょうか?自分で試したところ、値についてはちゃんと取得や設定などできていました。
根拠はないですが、もしかしたら未定義かもしれません。
また、iに0~3以外の値を入れた場合、危険かもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: クラスメンバ変数アクセスについて

#4

投稿記事 by softya(ソフト屋) » 9年前

とりあえず、メンバ変数を公開するよりバグが発生しやすそうなので、この設計は避けると思います。
バグを生み出さないためのカプセル化が行き過ぎると逆にコードが読みづらいバグ誘発剤になると思うわけです。

【補足】 なにか意図があって、こういう形を目指されたんだと思いますが、その意図を説明してもらわないと私には危険な設計に見えてしまいます。
意図が分かれば良い提案ができるかもしれません。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

各務
記事: 5
登録日時: 9年前

Re: クラスメンバ変数アクセスについて

#5

投稿記事 by 各務 » 9年前

返信ありがとうございます。

>h2so5 さん
Float4をそのまま使いたい場面があるのでこのような形を取らせて頂いていました。

>softya(ソフト屋) さん
そうですね。DirectXMathを使用するつもりで、簡単にやりたいことの概要を載せさせて頂きました。
X成分やY成分など単体で取得や設定したい場合もあると思いこのような設計を考えました。
代入演算子は書きましたがY成分だけを足したい場合に実体を作るのも嫌と思ったので…。

安全性はないようですね。別の設計を考えることにします。
解決とさせていただきます。
ありがとうございました。

各務
記事: 5
登録日時: 9年前

Re: クラスメンバ変数アクセスについて

#6

投稿記事 by 各務 » 9年前

すいません途中で送ってしまいました。

>みけCAT さん
やはり3以上を入れるとダメですよね…。気をつけていれば大丈夫だとは思いますが意図しない時に起こりかねませんよね…。
未定義とはどのへんでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: クラスメンバ変数アクセスについて

#7

投稿記事 by みけCAT » 9年前

各務 さんが書きました:やはり3以上を入れるとダメですよね…。
いいえ、3は最初に提示されたコードで入れられていて、問題は発見されていません。よって、この環境では大丈夫かもしれません。
各務 さんが書きました:未定義とはどのへんでしょうか?
以下の引用は、N3337(直リンク:http://www.open-std.org/jtc1/sc22/wg21/ ... /n3337.pdf)からの引用です。
5.2.1 Subscripting さんが書きました:The expression E1[E2] is identical (by definition) to *((E1)+(E2))
5.7 Additive operators さんが書きました:4 For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the
first element of an array of length one with the type of the object as its element type.

5 When an expression that has integral type is added to or subtracted from a pointer, the result has the type
of the pointer operand. If the pointer operand points to an element of an array object, and the array is
large enough, the result points to an element offset from the original element such that the difference of
the subscripts of the resulting and original array elements equals the integral expression. In other words, if
the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P))
and (P)-N (where N has the value n) point to, respectively, the i + n-th and i − n-th elements of the array
object, provided they exist. Moreover, if the expression P points to the last element of an array object,
the expression (P)+1 points one past the last element of the array object, and if the expression Q points
one past the last element of an array object, the expression (Q)-1 points to the last element of the array
object. If both the pointer operand and the result point to elements of the same array object, or one past
the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is
undefined.
いま、(&f.x)[2]という式を考えると、これは*((&f.x)+(2))と等価です。
f.xは配列ではないので、&f.xは要素数1の配列の先頭要素へのポインタとみなします。
(&f.x)+(2)は要素数1の配列の2番目(ただし先頭要素を0番目とする)の要素へのポインタになります。
しかし、要素数1の配列の最後の要素は0番目、最後の要素の1個次の要素は1番目なので、
「2番目の要素」はこの配列またはこの配列の最後の要素の1個次の要素の範囲に収まっていません。
よって、この計算結果のふるまいは未定義になります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

各務
記事: 5
登録日時: 9年前

Re: クラスメンバ変数アクセスについて

#8

投稿記事 by 各務 » 9年前

>みけCAT さん
ご回答ありがとうございます。
アライメント制御等していたので、Xを先頭に配列のように扱えるように思っていました。

勉強になりました、ありがとうございました。

アバター
usao
記事: 1887
登録日時: 11年前

Re: クラスメンバ変数アクセスについて

#9

投稿記事 by usao » 9年前

オフトピック
Float4 と Vector4 という2種類を存在させる意味が既にわからないのは私だけなのか…

アバター
milfeulle
記事: 47
登録日時: 10年前
住所: マリーランド
連絡を取る:

Re: クラスメンバ変数アクセスについて

#10

投稿記事 by milfeulle » 9年前

よくわからないんですが、これじゃダメなんですかね?

コード:

class Vector4 {
public:
	Vector4(float x, float y, float z, float w) {
		f.x = x;
		f.y = y;
		f.z = z;
		f.w = w;
	}

	float& operator [] (unsigned int i) {
		return f.data[i];
	}
	float operator [] (unsigned int i) const {
		return f.data[i];
	}

private:
	union {
		struct {
			float x, y, z, w;
		};
		float data[4];
	} f;
};
ζ*'ヮ')ζプログラミングはみんなで奏でるシンフォニー

各務
記事: 5
登録日時: 9年前

Re: クラスメンバ変数アクセスについて

#11

投稿記事 by 各務 » 9年前

返信ありがとうございます。

>usao さん
DirectXMathをDirectXTKを参考にして自分の使いやすいクラスとしてラップするつもりでいました。
C++なのでせっかくならばクラス化をと思いまして…。

>milfeulle さん
おお…、この方法は自分の中で理想的です…!
unionをこれまで触ってこなかったので思いつきませんでした。
配列として持っているので安全性も少なからず自分の書いたものよりあるはずです。

コード:

union
{
    struct {
        float x, y, z, w;
    };
} f;
のstructのところはFloat4でいこうと思います。
アクセス演算子?のところにも念のためにassertをしておくことにします。

この方法で行こうと思います。
回答していただいた方々、ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る