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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C++

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

Q&A

解決済

3回答

6466閲覧

C++ コンポジション、仮想関数とイ二シャライザについて

saito.kaz

総合スコア76

C++

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

0グッド

0クリップ

投稿2016/01/22 01:59

編集2016/01/22 03:33

いつもお世話になっております。
C++の学習を初めて1週間なので、質問が多くて申し訳ありません。
質問なのですが、コンポジションの場合、仮想関数をオーバーライドすることはできないのでしょうか。

*修正 : 回答を元に、エラー文、Workerクラスのプログラムを修正を行いました。

###前提・実現したいこと
下記のコードでは、phoneクラスを使って、Workerクラスでコンポジションを実装しています。
なぜか下記コードを実装したところ、[phoneクラスがすでに実装されている]と言われ、イニシャライザがうまく実装できません。
構文もあっていると思っているので、エラーの解決方法が分からないので、教えて頂けると幸いです。

###発生している問題・エラーメッセージ
Phone.cpp:40:21: warning: ISO C++11 does not allow conversion from string literal to 'char ' [-Wwritable-strings]
Phone p2(false, "p2","noraml2");
^
Phone.cpp:41:21: warning: ISO C++11 does not allow conversion from string literal to 'char ' [-Wwritable-strings]
Phone p3(false, "p3","noraml3");
^
2 warnings generated.
In file included from Worker.cpp:2:
./Worker.h:8:4: error: unknown type name 'Phone'
Phone phone;
^
Worker.cpp:16:61: error: use of undeclared identifier 'i'
Worker::Worker(int number, char
name, double salary):Phone(i,plan,pInfo){
^
Worker.cpp:16:63: error: use of undeclared identifier 'plan'
Worker::Worker(int number, char
name, double salary):Phone(i,plan,pInfo){
^
Worker.cpp:16:68: error: use of undeclared identifier 'pInfo'
Worker::Worker(int number, char* name, double salary):Phone(i,plan,pInfo){
^
Worker.cpp:32:9: error: exception specification in declaration does not match previous declaration
Worker::~Worker(){
^
./Worker.h:12:4: note: previous declaration is here
~Worker();
^
5 errors generated.
###ソースコード

<Phone.h> #include <string.h> class Phone{ public: Phone(); Phone(bool i, char* plan, std::string pInfo); ~Phone(); bool i; char* plan; std::string pInfo; void ShowPhone(); virtual void ShowData(); }; <Phone.cpp> #include <iostream> #include <string.h> #include "Phone.h" using namespace std; Phone::Phone(){ plan = new char[100]; cout << "this is constrcuter "<< "\n"; this->i = false; strcpy(this->plan, "normal"); this->pInfo = "nokia"; } Phone::Phone(bool i, char* plan, string pInfo){ this->plan = new char[100]; this->i = i; strcpy(this->plan, plan); this->pInfo = "nokia"; } Phone::~Phone(){ } void Phone::ShowPhone(){ cout << " i = " << this->i << "\n"; cout << " plan = " << this->plan <<"\n"; cout << " pInfo = " << this->pInfo <<"\n"; } void Phone::ShowData(){ cout << " This is ShowData " << "\n"; } int main(){ Phone p1; Phone p2(false, "p2","noraml2"); Phone p3(false, "p3","noraml3"); cout << "----------p2.ShowPhone();-------------------" << "\n"; p2.ShowPhone(); cout << "----------p3.ShowPhone();-------------------" << "\n"; p3.ShowPhone(); cout << "-----------------------------" << "\n"; p1.i = false; strcpy(p1.plan,"normal"); p1.pInfo = "nokia"; p1.ShowPhone(); cout << "-----------------------------" << "\n"; p2.ShowData(); return 0; } <Worker.h> class Worker{ public: int number; char* name; double salary; Phone phone; Worker(); Worker(int number, char* name, double salary); Worker(const Worker &obj); ~Worker(); }; #include <iostream> #include "Worker.h" #include "Phone.h" using namespace std; Worker::Worker(){ name = new char[80]; cout<< " This is Constructor " << "\n"; strcpy(name, "undifined"); number = 0; salary = 0; } Worker::Worker(int number, char* name, double salary):Phone(i,plan,pInfo){ cout<< " This is Constructor called Worker(int number, char* name, double salary):Phone(bool i, char* plan, string pInfo) " << "\n"; this->number = number; this->name = new char[100]; strcpy(this->name, name); this->salary = salary; } Worker::Worker(const Worker &obj){ cout<< " This is Copy Constructor " << "\n"; name = new char[80]; strcpy(name,obj.name); this->number =obj.number; this->salary = obj.salary; }; Worker::~Worker(){ delete[] name; cout << "デコンストラクタ" << "\n"; } /* void ShowData(Worker w2){ cout << "name = " << w2.name << "\n"; strcpy(w2.name,"AVD"); cout << "name = " << w2.name << "\n"; cout << "number = " << w2.number << "\n"; cout << "salary = " << w2.salary << "\n"; } */ int main(){ Worker w1; strcpy(w1.name,"Takayuki"); w1.number =10; w1.salary = 200; cout << " Before shwodata" << "\n"; //ShowData(w1); cout << " After shwodata" << "\n"; return 0; }

###補足情報(言語/FW/ツール等のバージョンなど)
paiza.io

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

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

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

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

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

guest

回答3

0

こんにちは。

11:22の質問への回答します。
途中でソースとエラーメッセージが変わっているので他の方と回答が大きく異なると思います。回答が意味不明になるような修正はよろしくないです。旧ソースとエラーメッセージを残して追記した方が良いように思います。

Worker::Worker(int number, char* name, double salary):Phone(i,plan,pInfo){

Phoneはメンバ変数名ではなくクラス名ですね? ということは、これは基底クラスとしてPhoneを指定する場合に使う構文です。

次に、i, plan, pInfoはWoker()のパラメータに含まれていないため、グローバル変数を探しに行きます。でも、グローバル変数にないので未定義エラーになります。これらもWoker()のコンストラクト時に指定したいのであれば、これらもパラメータに持つWorker()コンストラクタを別途定義する必要が有ります。
まとめると、例えば下記コンストラクタの追加が必要でしょう。(もちろん、Worker.hの宣言部とWorker.cppの呼び出し部の修正も必要です。)

C++

1Worker::Worker(int number, char* name, double salary, bool i, char* plan, string pInfo):phone(i,plan,pInfo){ 2(後略)

投稿2016/01/22 02:50

編集2016/01/22 02:51
Chironian

総合スコア23272

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

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

saito.kaz

2016/01/22 03:53

この場合、イニシャライザを使うと良いと書いてあり、上記コードのように記載しています。この場合、イニシャライザは使えないということでしょうか。
Chironian

2016/01/22 04:13

イニシャライザ使えますよ。でも、使い方を間違っています。 メンバ変数を初期化する時は、メンバ変数名を指定します。 基底クラスを初期化する時は、基底クラス名を指定します。 Workerは、Phoneクラス(頭文字が大文字)のメンバ変数phone(頭文字が小文字)を持ってますが、基底クラスを持ってませんね。 従って、初期化子でPhone(クラス名)を指定するとエラーになります。phone(メンバ変数)を指定すれば大丈夫です。
saito.kaz

2016/01/22 04:21

ご返信ありがとうございます。 コンポジションでも上記のように基底クラスを指定すれば、イニシャライザできると書いてあるのですが、これは間違えでしょうか。
saito.kaz

2016/01/22 04:25

多分、継承の際に使うイニシャライザと、コンポジションのときに使うメンバイニシャライザを勘違いしてました。 トライしてみます。
saito.kaz

2016/01/22 05:00

解決しました。 ありがとうございます。 メンバイニシャライザの定義とイニシャライザの定義を間違っており、理解することがでいました。 勉強になりました。 ありがとうございます。
guest

0

そのエラーメッセージだけではよくわからない場合、たいてい近くに同じ問題を基にした別のエラーメッセージがあって、それと関連付けて考えることで解決できます。

今回の場合、

./Phone.h:3:7: note: previous definition is here

class Phone{
^
Worker.cpp:7:18: error: type 'Phone' is not a direct or virtual base of 'Worker'
Worker::Worker():Phone(){
^~~~~

2つ目のWorker.cppでのエラーが発端です。
要は、Phoneクラスが定義されているヘッダファイルがWorkerクラスが定義される前に読み込めていないためのエラーです。正解を言ってしまうと

C++

1<Worker.cpp> 2#include <iostream> 3#include "Worker.h" 4#include "Phone.h" 5 67#include <iostream> 8#include "Phone.h" 9#include "Worker.h" 10

ということです。#includeディレクティブはコンパイルの際にそこに書かれているファイルをその場に読み込んでコンパイルしろ、とコンパイラに命令していることになりますので、順番を間違えると、今回のように定義していないクラスをメンバに持つクラスを作ってしまいます。
その時にコンパイラが勝手にPhoneクラスという基底クラスがあるものと解釈してコンパイルするために今回のエラーメッセージが表示されていると考えてください。

投稿2016/01/22 02:28

KoichiSugiyama

総合スコア3041

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

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

saito.kaz

2016/01/22 03:56

ありがとうございます。 上記のように致し、下記のエラーが発生しました。 そこで#includeの順序を変えています。
saito.kaz

2016/01/22 03:57

Phone.cpp:40:21: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] Phone p2(false, "p2","noraml2"); ^ Phone.cpp:41:21: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] Phone p3(false, "p3","noraml3"); ^ 2 warnings generated. In file included from Worker.cpp:2: ./Worker.h:8:4: error: unknown type name 'Phone' Phone phone; ^ Worker.cpp:17:66: error: expected '(' for function-style cast or type construction Worker::Worker(int number, char* name, double salary):Phone(bool i, char* plan, string pInfo){ ~~~~ ^ Worker.cpp:17:73: error: expected '(' for function-style cast or type construction Worker::Worker(int number, char* name, double salary):Phone(bool i, char* plan, string pInfo){ ~~~~^ Worker.cpp:17:75: error: use of undeclared identifier 'plan' Worker::Worker(int number, char* name, double salary):Phone(bool i, char* plan, string pInfo){ ^ Worker.cpp:17:81: error: unexpected type name 'string': expected expression Worker::Worker(int number, char* name, double salary):Phone(bool i, char* plan, string pInfo){ ^ Worker.cpp:33:9: error: exception specification in declaration does not match previous declaration Worker::~Worker(){ ^ ./Worker.h:12:4: note: previous declaration is here ~Worker(); ^ 6 errors generated.
saito.kaz

2016/01/22 05:00

解決しました。 勉強になりました。 ありがとうございます。
guest

0

ベストアンサー

ご質問内容、私の回答のあとで修正されましたか?
回答があった後には、修正した旨を一言添えていただかないと、回答内容がちぐはぐになって、他の方も困ると思います。


拝見しました。
>[phoneクラスがすでに実装されている]と言われ

<Worker.cpp> の

c++

1#include "Worker.h" 2#include "Phone.h"

で、"Worker.h" のなかの#include "Phone.h"でもPhone.hを読み込んでしまっているからでしょう。

対策としては
0. Phone.h が Worker.hに完全従属しているのであれば(Worker.h を利用する場合にだけ、Phone.h が利用される)、Worker.cpp のほうには #include "Phone.h" を書かない。
0. 各ヘッダファイルに、2度読みされないようにガードを入れる。http://www.g-ishihara.com/c_pp_01.htm

が挙げられます。

投稿2016/01/22 02:14

編集2016/01/22 02:28
hsk

総合スコア728

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

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

saito.kaz

2016/01/22 02:29

いくつか試行錯誤して、ミスを修正しておりました。 申し訳ありません。
saito.kaz

2016/01/22 03:58

エラー文もプログラム文を含め、すべてを変更しました。 お時間がありましたら、ご回答頂けたら嬉しいです。
saito.kaz

2016/01/22 04:16

#include <iostream> #include "Worker.h" のようにしました。 下記のようなエラーが発生しました。 Phone.cpp:40:21: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] Phone p2(false, "p2","noraml2"); ^ Phone.cpp:41:21: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] Phone p3(false, "p3","noraml3"); ^ 2 warnings generated. Worker.cpp:14:61: error: use of undeclared identifier 'i' Worker::Worker(int number, char* name, double salary):Phone(i ,plan ,pInfo){ ^ Worker.cpp:14:64: error: use of undeclared identifier 'plan' Worker::Worker(int number, char* name, double salary):Phone(i ,plan ,pInfo){ ^ Worker.cpp:14:70: error: use of undeclared identifier 'pInfo' Worker::Worker(int number, char* name, double salary):Phone(i ,plan ,pInfo){ ^ 3 errors generated.
saito.kaz

2016/01/22 05:00

解決しました。 ありがとうございます。 メンバイニシャライザの定義とイニシャライザの定義を間違っており、理解することがでいました。 勉強になりました。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問