私は疑問に出くわした本からいくつかの演習を行っています。クラス ( Stonewt )のフレンド関数として、いくつかの演算子のオーバーロードを定義しました。問題は、次のようなプロトタイプで発生します。
friend ostream & operator<<(ostream &os, Stonewt &st);
friend Stonewt operator+(Stonewt &st1, Stonewt &st2);
次のように、コンストラクターに依存して暗黙的な変換を行い、コンパイラーに作業を任せるとします (test1 と test2 はクラス オブジェクトです)。
cout << "Summing both weights: " << test1 + test2;
次のようなエラー メッセージが表示されます。
'std::basic_ostream' 左辺値を 'std::basic_ostream&&' にバインドできません
'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) の引数 1 を初期化します [with _CharT = char; _Traits = std::char_traits; _Tp = Stonewt]'
OTOH、次のようにすると、エラーは発生しません。
Stonewt test3 = test1 + test2;
cout << "Summing both weights: " << test3;
コンパイラが Stonewt オブジェクトを取得した場合、Stonewt& への変換を行うことができます (これが関数の期待です)。しかし、それ以外のものを取得すると、Stonewt& に到達するまでの手順を実行できません。(これと同じことが、operator* のような他の演算子のオーバーロードを使用する他のインスタンスでも発生します。double を配置し、コンパイラーがコンストラクターを介してそれを Stonewt に変換し、次に Stonewt& に変換することを期待すると、機能しません。Stonewt を配置する必要があります。物体)。
これは正しい動作ですか?何か助けはありますか?
必要な場合に備えて、プログラム全体を配置します。
クラス定義:
// stonewt1.h -- revised definition for the Stonewt class (for project Exercise 11.5.cbp)
#ifndef STONEWT1_H_
#define STONEWT1_H_
using std::ostream;
class Stonewt
{
public:
enum {Lbs_per_stn = 14}; // pounds per stone
enum Mode {STN, ILBS, FLBS}; // stone, integer pounds, and floating-point pounds modes
private:
int stone; // whole stones
double pds_left; // fractional pounds
double pounds; // entire weight in pounds
Mode mode; // state member
public:
Stonewt(double lbs = 0.0, Mode form = FLBS); // construct from pounds
Stonewt(int stn, double lbs, Mode form = STN); // construct from stones and pounds
~Stonewt(); // do-nothing destructor
void reset(double lbs = 0);
void reset(int stn, double lbs = 0);
void set_mode(Mode form);
Mode mode_val() const;
friend ostream & operator<<(ostream &os, Stonewt &st);
friend Stonewt operator+(Stonewt &st1, Stonewt &st2);
friend Stonewt operator-(Stonewt &st1, Stonewt &st2);
friend Stonewt operator*(Stonewt &st1, Stonewt &st2);
// conversion functions
explicit operator int() const;
explicit operator double() const;
};
#endif
メソッド + フレンド関数 + 変換関数の実装:
// stonewt1.cpp -- Stonewt class: methods, friend functions, and conversion functions implementation (compile alongside main.cpp)
#include <iostream>
#include "stonewt1.h"
using std::cout;
// construct from pounds (both arguments defaulted, form defaulted to FLBS)
Stonewt::Stonewt(double lbs, Mode form)
{
stone = int (lbs) / Lbs_per_stn; // integer division
pds_left = int (lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
mode = form;
}
// construct from stones and pounds (form defaulted to STN)
Stonewt::Stonewt(int stn, double lbs, Mode form)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
mode = form;
}
Stonewt::~Stonewt() // do-nothing destructor
{
}
// reset object data members (don't change mode)
void Stonewt::reset(double lbs)
{
stone = int(lbs) / Lbs_per_stn;
pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
pounds = lbs;
}
void Stonewt::reset(int stn, double lbs)
{
stone = stn;
pds_left = lbs;
pounds = stn * Lbs_per_stn + lbs;
}
// change object mode
void Stonewt::set_mode(Mode form)
{
mode = form;
}
// returns mode
Stonewt::Mode Stonewt::mode_val() const
{
return mode;
}
// friend functions
ostream & operator<<(ostream &os, Stonewt &st)
{
if (st.mode == Stonewt::STN)
os << st.stone << " stones and " << int(st.pds_left + 0.5) << " pounds.\n";
else if (st.mode == Stonewt::ILBS)
os << int(st.pounds + 0.5) << " pounds.\n";
else if (st.mode == Stonewt::FLBS)
os << int(st.pounds) << " pounds.\n";
else
os << "Invalid mode.";
return os;
}
Stonewt operator+(Stonewt &st1, Stonewt &st2)
{
Stonewt result;
result.stone = int(st1.pounds + st2.pounds) / Stonewt::Lbs_per_stn;
result.pds_left = int(st1.pounds + st2.pounds) % Stonewt::Lbs_per_stn + (st1.pounds + st2.pounds) - int(st1.pounds + st2.pounds);
result.pounds = st1.pounds + st2.pounds;
return result;
}
Stonewt operator-(Stonewt &st1, Stonewt &st2)
{
Stonewt result;
result.stone = int(st1.pounds - st2.pounds) / Stonewt::Lbs_per_stn;
result.pds_left = int(st1.pounds - st2.pounds) % Stonewt::Lbs_per_stn + (st1.pounds - st2.pounds) - int(st1.pounds - st2.pounds);
result.pounds = st1.pounds - st2.pounds;
return result;
}
Stonewt operator*(Stonewt &st1, Stonewt &st2)
{
Stonewt result;
result.stone = int(st1.pounds * st2.pounds) / Stonewt::Lbs_per_stn;
result.pds_left = int(st1.pounds * st2.pounds) % Stonewt::Lbs_per_stn + (st1.pounds * st2.pounds) - int(st1.pounds * st2.pounds);
result.pounds = st1.pounds * st2.pounds;
return result;
}
// conversion functions
Stonewt::operator int() const
{
return int(pounds + 0.5);
}
Stonewt::operator double()const
{
return pounds;
}
クライアント (未完成):
// main.cpp -- Exercising the revised Stonewt class: state member, operator overloadings (operator<<()
// replacing the show methods, operator+(), operator-(), operator*()) as friend functions.
#include <iostream>
#include "stonewt1.h"
#include <string>
int main()
{
using std::cout;
using std::cin;
using std::string;
cout << "***********************************************************************"
"*********";
cout << "*\n*\n*";
cout.width(35);
cout << "Menu:\n";
(cout << "*\n*").width(10);
(cout << "a. Reset").width(20);
(cout << "b. Select").width(20);
(cout << "c. Change mode").width(20);
(cout << "d. Show").width(0);
(cout << "\n*").width(10);
(cout << "e. Sum").width(20);
(cout << "f. Subtract").width(20);
(cout << "g. Multiply").width(20);
cout << "h. Menu";
cout << "\n*\n*\n";
cout << "***********************************************************************"
"*********\n\n";
Stonewt test1;
Stonewt test2;
Stonewt &sel = test1;
char ch {'z'};
cin.get(ch);
switch (ch)
{
case 'A' :
case 'a' : if (sel.mode_val() == 3 || sel.mode_val() == 2)
{
cout << "Enter the pounds: ";
double p {0.0};
cin >> p;
sel.reset(p);
}
else if (sel.mode_val() == 1)
{
cout << "Enter the stones: ";
int s {0};
cin >> s;
cout << "Enter the remaining pounds: ";
double p {0.0};
cin >> p;
sel.reset(s, p);
}
else
cout << "Wrong mode.";
break;
case 'B' :
case 'b' : {
cout << "Select object (1 for test1, 2 for test2): ";
int temp;
cin >> temp;
if (temp == 1)
sel = test1;
else
sel = test2;
break;
}
case 'C' :
case 'c' : {
cout << "Select the desired mode (STN, FLBS or ILBS): ";
string temp;
cin >> temp;
if (temp == "STN")
sel.set_mode(Stonewt::Mode::STN);
else if (temp == "ILBS")
sel.set_mode(Stonewt::Mode::ILBS);
else if (temp == "FLBS")
sel.set_mode(Stonewt::Mode::FLBS);
else
cout << "Wrong mode. " << sel.mode_val() << " retained.";
break;
}
case 'D' :
case 'd' : cout << sel;
break;
case 'E' :
case 'e' : cout << "Summing both weights: " << test1 + test2;
break;
case 'F' :
case 'f' : cout << "Subtracting the second weight from the first one: " << test1 - test2;
break;
case 'G' :
case 'g' : {
cout << "Choose a factor: ";
double temp;
cin >> temp;;;
sel = sel * temp;
break;
}
}
return 0;
}