新訂版More Effective C++ 演算子に関しての質問です。 – プログラミング – Home

通知
すべてクリア

新訂版More Effective C++ 演算子に関しての質問です。


迷ヤーズ
 迷ヤーズ
(@迷ヤーズ)
ゲスト
結合: 15年前
投稿: 3
Topic starter  

新訂版More Effective C++
「項目5:ユーザ定義の変換関数に気をつけよう」という部分で、
斯様な解説があるのですが、このまま、コンパイルをしますと、
Rational r(1, 2); この形を受け取るコンストラクタも無いので、
当然のことですが
error C2078: 初期化子の数が多すぎます。
error C2440: '初期化中' : 'int' から 'Rational' に変換できません。となります、
1, 2 を引き受けるコンストラクタとか、operator double() const;の意味が分らないの
ですが。
識者の方へ解説願えませんでしょうか、よろしくお願いします。

class Rational {
public:
operator double() const; // Rational をdouble に変換
};

この関数は次のような文脈で自動的に呼び出される。

/** More Effective C++ P23 演算子
*
*/
#include <iostream>
#include more_effective_cc2.h

int main() {
Rational r(1, 2); // r は1/2 を持つ
double d = 0.5 * r; // r をdouble に変換し、
// 次の乗算を行う
}


引用解決済
トピックタグ
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

> operator double() const;の意味が分らないのですが。

Rationalクラスのインスタンスが doubleにキャストされるときに使用される
オペレータ関数です。

> double d = 0.5 * r; // r をdouble に変換し、
> // 次の乗算を行う

の行で、インスタンス r がdoubleにキャストされるなら
関数 Rational::operator double() const;
の中身が実行されます。そうしてから 0.5 がpushされて
掛け算が実行されて、結果が d に格納されます(多分)。

ちなみに、これらのコードは原文のままでしょうか。
だとしたら自分としては「ずいぶん不親切なサンプルコードですね」
と笑っちゃうかも(^^;)。


返信引用
迷ヤーズ
 迷ヤーズ
(@迷ヤーズ)
ゲスト
結合: 15年前
投稿: 3
Topic starter  

仲澤@失業者 さんお世話になります。
原書ですが、ここから見ることができます。
http://robotics.dei.unipd.it/~filippo/Robocup/guide%202004/vari%20doc/MEffC++.pdf
p26 の当たりの解説が、当該コードにあたると思います。
さて、
>インスタンス r がdoubleにキャストされるなら
とのことですが、もしもこの意図に従うならば
やはり、この書き方でRational r(1, 2); double にキャストするには、コンストラクタで
この仕様を定義すればよいという、ことでしょうか?


返信引用
迷ヤーズ
 迷ヤーズ
(@迷ヤーズ)
ゲスト
結合: 15年前
投稿: 3
Topic starter  

このようなコードを書いてみましたが、どうも期待する動作にはなりません。
// double d = 0.5 * r;
コメントアウトすると斯様なエラーが出ます?
error LNK2019: 未解決の外部シンボル public: __thiscall Rational::operator
double(void)const (??BRational@@QBENXZ) が関数 _main で参照されました。
fatal error LNK1120: 外部参照 1 が未解決です。

#ifndef _INCLUDE_MORE_EFFECTIVE_CC2_H_
#define _INCLUDE_MORE_EFFECTIVE_CC2_H_

#ifndef _INCLUDE_MORE_EFFECTIVE_CC2_H_
#define _INCLUDE_MORE_EFFECTIVE_CC2_H_

class Rational {
public:
Rational();
double div(int lhs, int rhs);
Rational(int lhs_, int rhs_){ div( lhs_, rhs_ ); }
operator double() const; // Rational をdouble に変換
};

double Rational::div(int lhs_, int rhs_)
{
double result;
result = static_cast<double>(lhs_) / static_cast<double>(rhs_);
return result;
}

#endif // End of _INCLUDE_MORE_EFFECTIVE_CC2_H_

/** More Effective C++ P23 演算子
*
*/
#include <iostream>
#include more_effective_cc2.h

using namespace std;

int main() {
Rational r(1, 2); // r は1/2 を持つ
//double d = 0.5 * r; // r をdouble に変換し、
// 次の乗算を行う
}


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

何か根本的な勘違いをしているような気が...

class Rational { // for rational numbers
public:
Rational(int numerator = 0, // converts int to
int denominator = 1); // Rational
...
};
class Rational は有理数を表します。
コンストラクタには二つのデフォルト引数、つまり分母(denominator)、分子
(numerator)が必要です。
このRationalクラスの内部表現は記載されていませんが、後ろの方で
cout << r; // should print 1/2
と記載されていることから除算は実行せず、分母、分子をそれぞれ内部で保存している
ものと考えます。
つまり、
class Rational { // for rational numbers
private:
int numerator_;
int denominator_;
public:
Rational(int numerator = 0, int denominator = 1)
: numerator_(numerator), denominator_(denominator)
{}
...
};
のような感じ。

ここで、double d = 0.5 * r;という演算を実行したい、ということで、Rationalクラス
にoperator double() const;を定義します。
つまり、
class Rational { // for rational numbers
private:
int numerator_;
int denominator_;
public:
Rational(int numerator = 0, int denominator = 1)
: numerator_(numerator), denominator_(denominator)
{}
operator double() const
{ return (double(numerator_))/(double(denominator_)); }
};
これで、
int main() {
Rational r(1, 2); // r は1/2 を持つ
double d = 0.5 * r; // r をdouble に変換し、
// 次の乗算を行う
return 0;
}
はコンパイル/実行できるようになります。

でも、この「項目5:ユーザ定義の変換関数に気をつけよう」って言っているのは
下手にこの明示的変換関数operator double() const;を定義すると
cout << r; // should print 1/2
が1/2と印字されなくなるよ、っていっているんですよ。

この本より前にC++の基本的な勉強からやったほうがいいような気が...


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

なお、コメントアウトとは、
「プログラムのソースコードやソフトウェアの設定ファイルなどを部分的に修正する
時に、消したい内容を実際に消してしまうのではなく、コメント化することで一時的
に機能しないようにすること。」
なので、
> // double d = 0.5 * r;
> コメントアウトすると斯様なエラーが出ます?
> error LNK2019: 未解決の外部シンボル public: __thiscall Rational::operator
> double(void)const (??BRational@@QBENXZ) が関数 _main で参照されました。
> fatal error LNK1120: 外部参照 1 が未解決です。
はおかしな表現です。double d = 0.5 * r;がコメントアウトされていないため、
main から変換関数 double(void)const が呼び出された(参照)が、その関数自体が
存在しないため、外部参照が未解決となったのです。
普通は「このようなエラーが出たので一次的にコメントアウトしました。」等と使い
ます。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

あと、サンプルコードをよく見るとコードを全て載せているわけでは
ないことがわかるはずです。

途中に、・・・が入っているでしょう?
これはコードの極一部を提示していると言う意味だと思いますよ。
書いていない部分のコードはわかるよねと言う意味で省略していると
思います。ある意味、言われている本はその辺の行間を読める人を
対象にしていると思いますのでその部分が分からないのであれば、
読み解くのは難しいかもしれません。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました