トップ回答者
C1001の解決方法について

質問
-
こんにちは。
もうすぐお正月なのですが、質問をさせてください。VC++8.0で以下のソースをコンパイルするとC1001エラーが出てしまいます。ヘルプを見ると、コンパイルオプションを変更すると解決すると言ったようなことを書いていたのでいろいろと試しているのですがうまくいきません。
VC++6.0や7.1ではコンパイルできるので、オプション設定で何とかできるのではないかと思うのですが、どうすればコンパイルできるでしょうか?
~~~環境~~~
Windows XP Professional
Visual Studio 2005 Professional (SP1適応済み)
(Expressでも同じようです)
Win32のスタティックライブラリプロジェクトを作成してビルド~~~以下ソース~~~
class __declspec(dllexport) ClassA
{
public:
ClassA(){};
private:
ClassA(const ClassA& object){};
public:
virtual ~ClassA(){};
};class __declspec(dllexport) ClassB : public ClassA
{
public:
ClassB(){};
virtual ~ClassB(){};
};class __declspec(dllexport) ClassC : public ClassB
{
public:
ClassC(){};
ClassC(const ClassB& obj){};
virtual ~ClassC(){};
public:
ClassC func1(){
ClassC cl1;
return cl1;
}
ClassC func2(){
return func1(); // C1001
}
void func3(){
ClassC cl2;
ClassC cl3 = cl2; // C1001(ダイアログ付き)
}
};~~~~~~~
よろしくお願いします。
回答
すべての返信
-
良く分からないのですが、
private:
ClassA(const ClassA& object){};と、class ClassA の copy constructor を private にしているのは何故なのでしょう?
というのは、「__declspec(dllexport)」を全てコメントアウトしてみると分かるのですが、
return func1(); // C1001
や
ClassC cl3 = cl2; // C1001(ダイアログ付き)
のあたりで、インスタンスをコピーしようとして class ClassA の copy constructor が呼び出されようとしているのですが、private 宣言のために compile error が発生します。
private 宣言を外せば、「__declspec(dllexport)」が有効なままでも C1001 エラーは発生しないようです。
-
返信ありがとうございます。
privateは単純にClassAのコピーを作らせないためです。サンプルのクラスだとまったく意味はないのですが、実際に使用しているクラスだとこのあたりが必要になってしまっていて残念ながらはずせません。
ご指摘いただいたように[__declspec(dllexport)]をはずしてビルドしてみたところ、ClassBのコピーコンストラクタを作成しました、というメッセージが出ました。
ためしにClassBに以下のようなコピーコンストラクタを追加すると[__declspec(dllexport)]をつけていてもエラーは出ませんでした。
ClassB(const ClassB& object)この場合、ClassCのコピーを行うときに、ClassC(const ClassB& obj)が呼ばれず、ClassB(const ClassB& object)が呼ばれるようです。
VC7.1の場合、ClassB(const ClassB& object)が定義されていても、ClassC(const ClassB& obj)が呼ばれていたようなのですが、VC8.0の場合、ClassC(const ClassB& obj)という宣言はコピーコンストラクタとして認識されないということなのでしょうか?(そもそもコピーコンストラクタではない?)
-
-
既にRAPTさんがご指摘下さっていますが、
ClassC(const ClassB& obj)
は copy constructor ではありません。恐らくは type miss なのでしょうけれど、
ClassC(const ClassC& obj)
です。ですので、
ためしにClassBに以下のようなコピーコンストラクタを追加すると[__declspec(dllexport)]をつけていてもエラーは出ませんでした。
ClassB(const ClassB& object)この場合、ClassCのコピーを行うときに、ClassC(const ClassB& obj)が呼ばれず、ClassB(const ClassB& object)が呼ばれるようです。
class ClassC のインスタンスのコピーを行う時に、class ClassC の default の copy constructor が呼び出されてしまって、class ClassC は class ClassB から派生していますから class ClassB の定義している部分を copy しようとして class ClassB の copy constructor が呼び出されているのです。
# この場合、class ClassB の copy constructor が定義されていますから、class ClassA までは行かずに止まります。ので、compile error は出なかったのです。
-
VC7.1でチェックしてみました…。が、そのままのコードではなくて少しいじっています。
class ClassA {
public:
ClassA(){
std::cout << "ClassA::constructor" << std::endl ;
};
private:
ClassA(const ClassA& object){
std::cout << "ClassA::copy constructor" << std::endl ;
};
public:
virtual ~ClassA(){
std::cout << "ClassA::destructor" << std::endl ;
};
};class ClassB : public ClassA
{
public:
ClassB(){
std::cout << "ClassB::constructor" << std::endl ;
};
virtual ~ClassB(){
std::cout << "ClassB::destructor" << std::endl ;
};
};class ClassC : public ClassB {
private:
int m_iValueC ;
public:
ClassC() : m_iValueC (0) {
std::cout << "ClassC::constructor" << std::endl ;
};
ClassC(int iValue) : m_iValueC (iValue) {
std::cout << "ClassC::constructor" << std::endl ;
};
ClassC(const ClassB& obj){
std::cout << "ClassC::constructor??" << std::endl ;
};
virtual ~ClassC(){
std::cout << "ClassC::destructor" << std::endl ;
};
public:
ClassC func1(){
ClassC cl1;
return cl1;
}
ClassC func2(){
return func1(); // C1001
}
void func3(){
std::cout << "ClassC::func3() before: ClassC cl2;" << std::endl ;
ClassC cl2 (100) ;std::cout << "ClassC::func3() before: ClassC cl3 = cl2;" << std::endl ;
ClassC cl3 = cl2; // C1001(ダイアログ付き)
std::cout << "ClassC::func3() after: ClassC cl3 = cl2;" << std::endl ;
}
};int _tmain(int argc, _TCHAR* argv[])
{
ClassC theC ;theC.func3 () ;
return 0;
}標準出力の結果を追い掛けると(途中だけですが)、
ClassC::func3() before: ClassC cl3 = cl2;
ClassA::constructor
ClassB::constructor
ClassC::constructor?cl3 の定義時に = cl2 があるので、対応した constructor を呼び出そうとして、都合良く ClassC (const ClassB& obj) が呼ばれているようです。 ClassC である cl2 を ClassB で受けて初期化しているようですね。
# gcc4.x で禁止された cast-as-lvalue みたいなものなのでしょうか。C++ の規格が手元にないので何とも言えませんが。
いずれにせよ ClassB で受けてしまっているので、cl2 の m_iValueC の値は cl3 に反映できなくなってしまうわけですが…そこはかまわないのでしょうか?
-
返信ありがとうございます。
Takashi SAKAMOTO さんからの引用 いずれにせよ ClassB で受けてしまっているので、cl2 の m_iValueC の値は cl3 に反映できなくなってしまうわけですが…そこはかまわないのでしょうか?
ClassCには変数は無いので問題はありません。
Takashi SAKAMOTO さんからの引用 cl3 の定義時に = cl2 があるので、対応した constructor を呼び出そうとして、都合良く ClassC (const ClassB& obj) が呼ばれているようです。 ClassC である cl2 を ClassB で受けて初期化しているようですね。
この動作なのですが、以下のような記述でよいでしょうか?
ClassC cl2;
ClassC cl3 = *( (ClassB*) (&cl2) );