質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

90.61%

  • C

    3570questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3340questions

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

  • GCC

    138questions

    GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

テンプレートクラス メンバにアクセスできない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 535

strike1217

score 552

リンク内容
前回の問題に類似します。

template <class Param>
class func{
protected:
     Param _max;
     Param* _set;
     Param _num
....
}

template <class Param>
class func2 : public func<Param> { // 継承
public:
   void test();
...
}

template<class Param>
void func2<Param>::test(class func<Param> *s1, class func<Param> *s2){
    int n = (s1->_max < s2->_num) ? s1->_max : s2->_num;

    for(auto i = 0; i < n; i++)
        s1->_set[i] = s2->_set[i];
    s1->_num = n;
}


このコードはエラーです。

クラスを関数のパラメータにしています。
s1->_max, s2->_num などの部分ですね。
protected継承を行っているのですが、テンプレートなので、thisを付けなくていけないのですが・・・
リンク内容

今回のような場合、どこにthisを付ければ良いのでしょうか??
this->s1->_max  // error!
s1->this->_max  // error!

[  error: ‘int func<int>::_max’ is protected within this context  ]
[  declared protected here Param _max;  ]

privateやprotectedではなく、publicにすれば解決するんですが・・・
アクセス制限の方でちょっとpublicにするのは・・・って感じです。

friendでもできるのですが、継承してprotectedにしても可能なのではないかと思いまして・・・
しかし、テンプレートにするとできません。
protectedの問題を解決できません。
このようなメンバにはどのようにしてアクセスすれば良いのでしょうか??

教えてください。

[追記]
thisを付けると継承したクラス内のメンバ変数にアクセスすることになり、パラメータの方ではない・・・のですね。

すると・・・継承によって他のオブジェクトのアクセス権を獲得するのは無理・・・ということですかね。
friendに頼らないと不可能・・・ぽいかなぁ

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

こんにちは。

とりあえず、継承したクラス・テンプレートのメンバ変数にアクセスするには、下記記述でできます。

template<class Param>
void func2<Param>::test(class func<Param> *s1, class func<Param> *s2)
{
    this->_max = 1;
    func2<Param>::_num = 1;
}

しかし、たぶん聞きたいことはこのようなことではないような印象を受けます。
どうも本質的な部分を勘違いされているっぽいです。

継承は、ある意味名前無しのメンバ変数を定義しているのと近いです。

#include <iostream>

struct Base
{
    int data0;
};

struct Derived : public Base
{
    int data1;
};

struct Included
{
    Base    base;
    int     data1;
};

int main()
{
    std::cout << sizeof(Derived) << "\n";
    std::cout << sizeof(Included) << "\n";
}


上記のDerivedとIncludedの「メモリ・レイアウト」は同じです。data0, data1の順で並んでいます。
IncludedはBaseクラス型のメンバ変数に名前baseがついています。名前がついているので複数のBaseクラス型の変数を定義できます。
DerivedはBaseクラスを含んでいますが、継承であるため名前がありません。名前がないので継承できるものは1つだけです。

というような関係を定義するのが継承です。

friendでもできるのですが、継承してprotectedにしても可能なのではないかと思いまして・・・

friendでできることを継承してやろうとする発想が誤りなのです。
friendは単にアクセス制限を緩めるための仕組みです。継承のようにメモリ・レイアウトを伴う「実体」を定義するものとは概念が全く異なります。


ところで基底クラスがクラス・テンプレートだった場合、いつものようには基底クラスのメンバ変数にアクセスできません。リンク先に書かれているように「this->をつけるかBASE<T>::を付ける必要があるっぽい」です。

クラス・テンプレートは特殊化や部分特殊化できるため、どの定義が選択されるのか実体化されるまで決定できません。そのため、指定したメンバ変数があるかないか分からないのでコンパイルできないということのようです。
this->や基底クラス::は、実体化するまでは「あるかないか判らなくてもよい」ようにする効果があるようです。
詳しくはテンプレートの派生クラスから親クラスのメンバへのアクセスが判りやすいかも。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/10 22:47

    ふむーー。
    継承によってオブジェクトのアクセス権を獲得するのは無理ということですよね?

    friendを継承するというやり方もあるようです。
    http://d.hatena.ne.jp/aki-yam/20100420/1271775548

    やはりfriendに頼らないとダメそうですね。

    キャンセル

  • 2018/01/11 00:31 編集

    > friendを継承するというやり方もあるようです。

    単にクラスをfiriend指定して、そのクラスのメンバ関数を呼び出してアクセスしているだけです。
    至極普通の使い方と思います。

    なお、そのクラスを派生したクラスから、他のクラスのprivateメンバへアクセスしていると考えるのは誤りと考えたほうが好ましいと思います。
    そのように表現すると、public関数でアクセスしているprivateメンバは、他のクラスからアクセスできるということになります。それはオブジェクト指向プログラミングの隠蔽を破壊する考え方です。

    > 継承によってオブジェクトのアクセス権を獲得するのは無理ということですよね?

    継承しても基底クラスのprivateメンバにアクセスできるわけではないです。
    あっ、基底クラスのprotectedメンバにはアクセスできますね。
    Baseクラスを派生したDerivedクラスは、「自分」の中にあるBaseクラスのprotectedメンバにアクセスできます。しかし、他のDerivedクラスのオブジェクトの中にあるBaseクラスのprotectedメンバにアクセスできません。と思ったら出来ました。これは知らなかった。
    https://wandbox.org/permlink/pdhQ6AzkxHip4CE5

    更にテンプレートにすると https://wandbox.org/permlink/5Tt0oFQUyLObGxUE
    他のオブジェクトからアクセスする時は、thisや基底クラス指定はいらないようですね。
    先程のリンク先にあるように、thisの場合と同様オブジェクト経由でのアクセスですから、名前解決がテンプレートの実体化より後になるからでしょう。

    キャンセル

  • 2018/01/11 14:21

    クラスの継承か、friendかどちらにしてもアクセス権の獲得はカプセル化を破壊するため良くない・・・

    そうすると、chironianさんなら今回のtestメンバ関数のようにクラスを渡して処理するような関数はどのようにして実装しますか??

    キャンセル

  • 2018/01/11 16:54

    privateメンバやprotectedメンバのアクセス権を獲得するという方法は、全てカプセル化を破壊する方法ですね。カプセル化するべき時にまで適用するとアウトです。でも、カプセル化する必要性が低い時に適用してもセーフと私は考えます。リンク先は、一般解として提示してあったのでアウトと感じました。

    > chironianさんなら今回のtestメンバ関数のようにクラスを渡して処理するような関数はどのようにして実装しますか??

    例えば、ライブラリの内部からはアクセスできるが、ライブラリの外部からはアクセスできないメンバを定義したいケースがありますね。恐らく希望されている使い方は、このようなレベル分けして、一部のクラスからのみアクセスでき、他のクラスからはアクセスできないようにしたいのだと思います。そのための機能がfriendですね。ライブラリ内部からのアクセス許可であれば、許可したいクラスを全て把握できますから、概ね有用です。

    friendで対応できない場合(ライブラリの外部の一部からprivateメンバにアクセスしたいケース)は、カプセル化を断念するかも知れません。設計を見直してそもそも外部からのprivateメンバアクセスを不要とするのが理想ですが、なかなかそうもできない場合がありますし。

    キャンセル

  • 2018/01/11 16:59

    今回の場合は、friendで実装するのが良いということですね。
    わかりました。
    継承によってアクセス権を獲得するのはやめてfriendにします。

    キャンセル

+1

とりあえず、仮引数内にclassは必要ありません。
あってもいいですが、タイプ数の増加はコンパイルエラーの増加につながりますので、省いてしまうことをお勧めします。

さて、継承を利用して変数へのアクセスをしたいとのことですが、
求めている答えとは遠いかと思いますが、私見を述べさせていただきます。

継承を利用して変数へのアクセスするのはオブジェクト指向のカプセル化の概念に反するものだと思います。
(仕様上どうしても突破したい場合のためのfriendだと考えています。)

テンプレートクラスfuncに対する変更処理はfuncに持たせるべきであり、func2funcに対する特定の操作を纏めたクラスである場合、func2funcが持つ機能を呼ぶにとどめるべきだと考えます。
例えば、こうすればわざわざ親クラスの変数にアクセスせずとも事足りるはずです。

template <class Param>
class func{
public:
    void Union(const func<Param> *);
    func<Param>* difference(const func<Param> *);

    void test(func<Param> *s2){
        int n = (_max < s2->_num) ? _max : s2->_num;

        for(auto i = 0; i < n; i++)
            _set[i] = s2->_set[i];
        _num = n;
    }
protected:
    Param _max;
    Param* _set;
    Param _num;
};

template <class Param>
class func2{
public:
    void test(func<Param> *s1, func<Param> *s2){
        s1->test(s2);
    }
    func<Param>* difference(func<Param>* s1, const func<Param>* s2, const func<Param>* s3){
        auto ret = s1->difference(s2);
        ret->Union(s1->difference(s3));
        return ret;
    }
};

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/10 23:05 編集

    ふむふむ・・・
    なるほど!

    funcとfunc2の持つ機能を分離しておいたほうが分かりやすいと思ったのですが・・・
    結構難しいですね。

    「func2はfuncが持つ機能を呼ぶにとどめるべきだと考えます。」
    参考にさせてもらいます。

    キャンセル

  • 2018/01/11 14:33

    friendによる実装はできるだけ避けるべきなんでしょうか??

    キャンセル

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

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 受付中

    C++ variadic template template argument that match...

    I was wondering if it's possible to write a template function that can take any other arbi

  • 解決済

    シングルトンパターンを持つ基底クラスを継承したい

    今作成しているプログラムでシングルトンパターンを持つ基底クラスを継承したクラスを作る必要が出てきたので,こちらのサイト(http://glass5er.hatenablog.com

  • 解決済

    抽象クラスのコピー方法(java)

    前提・実現したいこと Javaで抽象クラスの変数を格納した新たなインスタンスをコピーして返却する方法を模索しています。 イメージは以下のような形です。 abstract 

  • 解決済

    Java 子クラスを介して親クラスのメソッドにアクセスする処理について

    質問 Java 継承関係にあるクラスの扱いについて 下記のように、子クラスに個別の処理を、 親クラスに共通の処理を実装した際に、メインのクラスから子クラスのmethodAを介し

  • 解決済

    平均と最大のメソッド、配列についてです。

    市町村のデータをソートし、その平均と最大、最小を求めたいのですが、 平均と最大がうまくできません。 平均は"二項演算子'+'のオペランド型が不正です"と表示され、intからTown

  • 解決済

    クラスの静的変数でエラー

    基本クラスとそのクラスの派生クラスのオブジェクトのメンバー変数を共有したいのですがstaticで宣言したらエラーが起こりました ほかの変数などは省きます class Acl

  • 解決済

    staticなクラス変数について

    非常に初歩的な質問で恐縮なのですが、例えば生成されたインスタンスの数などの、Count的なstaticクラス変数をもたせたい場合、 その値はどのようにして更新すればいいのでしょうか

  • 解決済

    C++ メインクラスと内部クラスの関係について

     前提・実現したいこと 度々 お世話になっております。よろしくお願いいたします。 現在、バイナリファイルを読み込み、解析してテキストファイルへ出力するプログラムを作成中です。

同じタグがついた質問を見る

  • C

    3570questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • C++

    3340questions

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

  • GCC

    138questions

    GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。