新規で作成したソースファイルにある自作関数から、Viewクラスのメンバ関数を呼び出
したのですが、プログラムを実行するとDebug Assertion Failedとエラーが出ます。
エラーはそのViewクラスのメンバ関数内にあるGetDocument()で起きています。
void C**View::A()
{
GetDocument()->B();
(省略)
}
ViewソースでC**View *cと宣言し、新規で作成したソースファイルにextern
C**View *cと宣言して、自作関数内で c->A(); でViewクラスの関数を呼び出していま
す。
デバッグをすると下のif (m_pHashTable == NULL)というところでAccess Violation
0xC0000005になります。
void* CMapPtrToPtr::GetValueAt(void* key) const
// find value (or return NULL -- NULL values not different as a result)
{
if (m_pHashTable == NULL)
return NULL;
UINT nHash = HashKey(key) % m_nHashTableSize;
// see if it exists
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc-
>pNext)
{
if (pAssoc->key == key)
return pAssoc->value;
}
return NULL;
}
Viewクラスの違うメンバ関数からそのメンバ関数を呼び出したらエラーは出ず、プログ
ラムは実行できました。
開発環境は
Windows XP
Microsoft Visual C++ 6.0 MFC
です。
どのように解決すればよいのか教えてください。
幾つか不明な内容も有りますけれど、
「ViewソースでC**View *cと宣言し」をグローバル変数と仮定して
cが指し示すインスタンスはいったいどのタイミングで設定されているのか?
そのインスタンスは、ドキュメント テンプレートで関連付けられた物なのか?
と言う部分が気にかかります。
GetDocumentと言う関数はViewとDocumentが関連付けられている状態にある事が
前提になりますからきちんと関連付けが行なわれていないViewでGetDocumentを
行なっても言われているような状況になると思います。
PATIOさん、早速の返信ありがとうございます。
ただ
>cが指し示すインスタンスはいったいどのタイミングで設定されているのか?
>そのインスタンスは、ドキュメント テンプレートで関連付けられた物なのか?
の意味がよくわかりません。僕は、C**View *cはViewソースのヘッダーの宣言と一緒
にしています。extern C**View *cも同様です。タイミングとか考えていません。
PATIOさんなら新規で作成したソースファイルにある自作関数から、Viewクラスのメンバ
関数を呼び出すにはどのようにしますか?
PATIOさんが示している
>cが指し示すインスタンスはいったいどのタイミングで設定されているのか?
つまり簡単に言えばポインタ初期化はいつ行ってますかと言うことです
tetuさんの説明で行けば
------------------
#include ”View-A”
Void main(Void)
{
C->A();
}
------------------
とやっているが何がいけない、と聞こえます
------------------
Void main(Void)
{
C = (C**View)GetDocument(); ←ここは何時行ってるのかな?
C->A();
}
------------------
前者のような記述になっているため、ポインタの参照範囲外になって
例外エラー起こしてるんじゃないですか
>タイミングとか考えていません。
端だけとってますけど、「考えてません」はマズイと思いますよ
「ANSI C言語からやり直せ!」って怒られますよ
作ろうとしてるアプリの関数関係図を簡単な線でよいから絵してみると
良いんじゃないですかね
C**View *c;
ってグローバル変数か?
推測ですけど
cの値がNULLとか不正な値になっている時に起きるエラーっぽいな。
c->A()を実行は出来るが、cのメンバ変数(m_pHashTable)にアクセスした時点でエラー
になっているので。
c=~;および~の初期化が行われる前にc->A();を実行しているんじゃないの。
初期化が終わる前にc->A();を実行しないようにするしかない気がする。
自作関数だってどこからか呼び出されるわけで、その呼びだす処理が早すぎるのかな。
既に皆さんがレスをつけていますけれど、
単純にポインタ変数を宣言しただけだと中身は空だからポインタしては
使える状態になっていないと言う話です。ポインタはきちんと指し示す先を
設定してからでないと使えません。
だから、設定は何時やってるのと言う意味です。
もしこの意味が分からないなら本気でC++言語の勉強をした方が良いです。
入門書等でポインタの勉強をしっかりしないと後々苦労する事になります。
私ならViewの関数を直接呼び出す必要があるような構成にそもそもしないと
思います。クラスのポインタが必要になると言う事は呼び出す側は、
他のクラスもしくはグローバル関数と言う事ですよね。
Viewの関数を直接呼び出してしまうと自作のクラスとViewのつながりが強くなり
過ぎてモジュール化が出来ません。逆に新しく作ったと言うクラス?関数?は
本当にViewとは独立に作る必要があったのかなぁと言う気もします。
みなさん返答ありがとうございます。
ポインターに値を渡していないのが問題なのは分かったのですが。
C = (C**View)GetDocument();
とコードを入れても「'GetDocument()'定義されていない識別子です」とコンパイルエラ
ーが出ます。
C = (C**View*)C->GetDocument();
にしたらコンパイルエラーは出なかったのですが、実行したら前回と同じ結果でした。
どのようにしてポインタに値を入れればいいのですか?
C = (C**View)GetDocument();
は新規ソースのextern C**View *cの宣言のあとに入れました。
MFC触る前にC++の文法勉強して下さい
>C = (C**View)GetDocument();
>とコードを入れても「'GetDocument()'定義されていない識別子です」とコンパイルエ
ラ
ーが出ます。
>
>C = (C**View*)C->GetDocument();
>にしたらコンパイルエラーは出なかったのですが、実行したら前回と同じ結果でし
た。
>
>どのようにしてポインタに値を入れればいいのですか?
この程度のことも理解してない状況から,人に聞くだけで何とかしようとしてたらきり
がない
ぶっちゃけ
あなたのプログラム全体を知っているわけじゃないから
そんな局所を示されても把握できないよ。
どのファイルでどんなことしたくて
どのファイルでどんな記述しているのか整理してくれ。
それとクラスとオブジェクトの関係も整理(理解や把握)してくれ。
> C = (C**View)GetDocument();
GetDocumentって何?(嫌味っぽい聞き方だけど気にするな)
Viewクラスのメンバ関数内にあるGetDocumentか?
それならViewクラスのメンバ関数内からしかGetDocumentを呼び出せないよ。
そもそも
GetDocumentってCDocument系のオブジェクトを得るものでしょ。
Cって何?(嫌味っぽい聞き方だけど気にするな)
まったく別物の(CHogeView*)にキャストできないよ。
# ポインタのキャストはコンパイル出来てしまうが確実にまずい。
> C = (C**View*)C->GetDocument();
これは先に説明したキャストできないっていうのとは別に
もう一つ問題がある。
Cが使えないからCを使えるようにするための処理なのに
『C->GetDocument』ってCを使うなよ。
以下推測
他人のプログラムなんてよくわからないので
推測だから合っているかわからんよ。
制限事項
CHogeViewのオブジェクトは一つしか作られない。
CHogeViewの初期化が終わる前にgpCを使用してはいけない。
CHogeViewが終了中あるいはオブジェクトがなくなってからgpCを使用してはいけない。
-----HogeView.cpp-----
extern CHogeView * gpC;
CHogeView::CHogeView()
{
gpC = this;
}
-----other.cpp-----
#include HogeView.h
CHogeView * gpC;
--------------------
念のための確認なんだけどさ
その自作関数がどういうタイミングで実行されるのか知らないけどさ
プログラム開始時にはCHogeViewはまだ存在しないんだよ。
>新規ソースのextern C**View *cの宣言のあとに入れました。
すっげー気になるのだけど
「extern」の使う意味わかって使ってますかね
「*c」は外部に定義されていることうを示しているから
コンパイラーへの指示として
コンパイル時には評価(妥当性)チェックしないで通してください
と言ってるようなことにもなるんですよ
つまり自分(hoge.cpp)以外のソースではきちんと
コンパイル評価され正しく動作可能なものですと宣言してるんですよ
自分ソース上では間違いがなくても外部ソースで間違いがあれば
当然実行時エラーになります
がしかし tetuさん の使い方は大間違いだと思いますよ
MSDNを持ってますよね
「VSWAP」と言うサンプル探してみてください
tetuさんの使い方とはかなり違いますが、tetuさんのやりたいことと
かなり似た動作をしてくれるものと思います
参考にしてみてください
他の回答者の方々の中には良いサンプルとはいえないと言う方もいますが
今のtetuさん にとってはかなり良いサンプルになるのではないでしょうか
みなさん丁寧にお答えいただき、ありがとうございました。
wclrp ( 'o')さんに教えていただいたコードを参考にプログラミングしたところ解決す
ることができました。