質問するログイン新規登録
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

4回答

4887閲覧

c++のクラスのメンバ変数を外部から読み取り専用にしたい

KonjacDesert

総合スコア14

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2019/04/05 08:24

0

0

クラスのメンバ変数を外部から読み取りしたいです.

たくさん変数があるので,できればゲッターを作りたくありません.
内部からのみ読み書きが可能で,外部からは読み取り専用にしたいです.
この状態にできればprivateかpublicかは問いません.

友人にはあきらめろと言われましたがどうしても気になったので質問させていただきました.よろしくお願いします.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

五年も前にこんなの書きました。
これをちょっといぢると:

C++

1#include <functional> 2 3template<class T> 4class property { 5private: 6 std::function<T()> get; 7public: 8 property(const std::function<T()>& getter) : get(getter) {} 9 T operator()() const { return get(); } 10 operator T() const { return get(); } 11 typedef T value_type; 12}; 13 14#define GET_PROPERTY(X) X([this]() {return X##_; }) 15 16// おためし 17#include <iostream> 18#include <string> 19#include <chrono> 20#include <ctime> 21 22class person { 23private: 24 // プロパティ名に'_'を付けること。 25 std::string name_; 26 int age_; 27 28public: 29 person(const std::string& n, int a) : 30 name_(n), GET_PROPERTY(name), 31 age_(a), GET_PROPERTY(age), 32 // 引数を取らない関数ならなんでも♪ 33 now([]() -> std::string { 34 std::time_t t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); 35 return std::ctime(&t); }) {} 36 property<std::string> name; 37 property<int> age; 38 property<std::string> now; 39}; 40 41int main() { 42 using namespace std; 43 person adam("adam", 20); 44 int age = adam.age; // do this 45 cout << adam.name() << " is " // or this 46 << age << " years old at " 47 << adam.now() << endl; 48}

投稿2019/04/05 11:47

編集2019/04/06 02:29
episteme

総合スコア16612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

書きたくない、って言っても書くしかないのがC++です。
一回書いたら終わりなので根気よくgetterを作るのが得策です。

一応、defineで作る方法を書いてみましたが、
どっちかというとエディタの置換を使って機械的に生成したほうがトラブルは少ないでしょう。

#include <iostream> #include <vector> #define GETONLY(T, NAME) private: T NAME; public: const T& get_##NAME() const {return (NAME);} class X{ GETONLY(int, n); GETONLY(std::vector<int>, list); public: X():n(10),list(){} }; int main() { X x; std::cout << x.get_n() << std::endl; }

(出来合いのライブラリのように)クラスを書き換えることは出来ないがprivate領域の値が知りたい
デバッガのような使い方として値を見たい、という話なら、一応闇魔法はあるので紹介だけしておきます。

http://d.hatena.ne.jp/redboltz/20120111/1326292284

投稿2019/04/05 09:47

izmktr

総合スコア2856

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

こんにちは。

私もマクロで量産に賛成です。参照はインラインで定義できるようです。(できないと思ってましたが、C++11でできるようになっているみたいです。)
しかし、残念オーバーヘッドが結構あるので、getter量産の方が良さそうです。

C++

1#include <iostream> 2 3#define READ_ONLYXX(dType, dName) private: dType dName##_; public: dType const& dName = dName##_; 4 5class Foo 6{ 7 READ_ONLYXX(int, bar); 8public: 9 Foo() : bar_(123) { } 10}; 11 12int main() 13{ 14 Foo foo; 15 std::cout << foo.bar << std::endl; 16 std::cout << sizeof(foo) << std::endl; 17// foo.bar = 456; 18}

wandbox


【追記】
catsforepawさんのコメントで気がついたのですが、1つ見落としていました。
コピー・コンストラクタでコピーできてしますのですが、コピーされた方の参照は、コピー元のメンバ変数を参照します。かなり危険なのでこれはコピー禁止(コピー・コンストラクタをdeleteするなど)しない限り使わないほうが良いです。(参照メンバがあるとコピー代入演算子は自動生成されないです。)

wandbox

投稿2019/04/05 09:05

編集2019/04/06 03:58
Chironian

総合スコア23274

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2019/04/05 09:18

const参照にしないと foo.bar = 456 が通ってしまうのではないでしょうか。
KonjacDesert

2019/04/05 09:32

constを付けたら書き込み不可になりました!ありがとうございます.
Chironian

2019/04/05 10:17 編集

LouiS0616さん ご指摘ありがとうございます。最初const付けていたのですが、const無し参照でもエラーでないのかな?っと試したあと、コピペしてしまったようです。お恥ずかしい。 サンプル・ソース修正しました。
catsforepaw

2019/04/06 01:06

const参照で読み取り専用にする方法だと、オブジェクトのコピーの際、参照先が自分のオブジェクトではなくコピー元のオブジェクトの方に書き換わってしまうという、重大なバグが生じることになります。 それを回避するには、コピーコンストラクタとoperator =を適切にオーバーロードする必要がありますが、そうなるとマクロ一つでは対処不可能です。
Chironian

2019/04/06 03:53

catsforepawさん フォローありがとうございます! 見落としてました。確かに危険ですね。 https://wandbox.org/permlink/ov1yMh0vYdPFDYye twshelp1117さん、折角BA頂いたのに申し訳ない。このテクニックは危険です。マクロでgetterを定義するのがベストな気がします。
guest

0

たくさん変数があるので,できればゲッターを作りたくありません.

プリプロセッサマクロでgetterを量産する、というのも1つの選択肢かもしれません。

投稿2019/04/05 08:29

maisumakun

総合スコア146738

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KonjacDesert

2019/04/05 08:54

その場合型ってどうやって指定すればよいでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問