DLL作成の機会がいろいろ調べているのですが、教えていただきたいことがあります。
1.インポートライブラリについて
 Windowsで暗黙的リンクでDLLをリンクする場合、
 インポートライブラリを利用するようですが、
 これは、DLL内のポインタと関数名を紐付けるような
 役割だと想定しています。
 仮に関数等ヘッダーで公開されている部分以外で
 DLLを更新した場合、インポートライブラリも
 再リンクするような場面があるのでしょうか。
 特に再リンクしなくてもDLLの更新が反映されたので・・
2.DLLのクラスの継承について
 DLL内に作成したクラスを継承することは不可能ですかね。
 DLLが更新された場合、インスタンスのイメージが違うため
 newやdeleteの処理で当初リンクしたインスタンスのイメージで
 行いますよね。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

>>"DLLのデーター"は”アプリのデーター領域”に配置される


>>という認識は間違いですか?

>間違いですね。(あっさり)

間違いですか。
では、"DLLのデータ"はどこに配置されるのでしょう?
呼びだし側に"DLL専用”の領域が新規にできるのですか?

できたら論拠となるMSDNのページを示して頂きたいです。
(日本語が良いですが、機械翻訳でわかりずらいページも多いです。
でしたら、英語でも構いません。)

>継承クラスをインスタンス化したときに
>領域が取られるわけですが、DLLのインスタンス部分の
>サイズはDLLによって定義されるのではないか

具体的に考えましょう
class Base
{
int m_BaseMember1;
};

なるクラスがDLLからエクスポートされているとします。
clas Ext : publc Base
{
int m_ExtMember1;
}
という風にアプリで派生させ、Extのオブジェクトを作成したとします。
int = 32ビット前提で考えますと
Baseオブジェクトの大きさは4バイト
Extオブジェクトの大きさは8バイトです。
(Base部分4バイト、Ext独自部分4バイト)

今Baseを修正し, int m_BaseMember2を追加したとします。
つまり
class Base
{
int m_BaseMember1;
int m_BaseMember2;
};

となったとします。
Extには変更なしとします。

新たなExtのサイズは12バイトです。
(Base部分8バイト、Ext独自部分4バイト)

このように基本クラスのインスタンスが
派生クラスのインスタンス中に完全に取り込まれるのは
DLLだろうと普通のアプリだろうと同様です。

DLLの場合は、
(基本クラスを取り込まずに)
ポインタでつなぐので
基本クラスのサイズが増えても
派生クラスのサイズは影響を受けない

などとはなっていません。
    • good
    • 0
この回答へのお礼

返答が遅くなり申し訳ないです。
>このように基本クラスのインスタンスが
>派生クラスのインスタンス中に完全に取り込まれるのは
>DLLだろうと普通のアプリだろうと同様です。
ではやはり、基本クラスの更新に伴って、派生クラスのコンパイルが必要に
なってくるのですね。
ありがとうございます。

お礼日時:2009/05/26 15:31

>アプリで定義した継承クラスを new した場合、


>DLLで定義した基底クラスのインスタンスはDLLのデーター領域にでき、
>アプリで定義した継承クラスの部分はアプリのデーター領域にできる・・?

あのーーー
"DLLのデーター領域"と”アプリのデーター領域”の違いがよくわかりません。
説明をお願いします。

http://msdn.microsoft.com/ja-jp/library/h90dkhs0 …
によりますと

”Win32 DLL は、呼び出し側プロセスのアドレス空間に割り当てられます。
既定では、DLL を使用するプロセスごとに、
すべての DLL のグローバル変数および
静的変数のインスタンスが作成されます。”

素直によむと
DLLのデータは呼び出し側プロセス(アプリのことですね)
のデータ領域に配置される
ように解釈できます。

ですから、私には
"DLLのデーター領域"と”アプリのデーター領域”の違いがわかりません。
"DLLのデーター"は”アプリのデーター領域”に配置される
という認識は間違いですか?
    • good
    • 0
この回答へのお礼

間違いですね。(あっさり)
というより表現が適切ではなかったと思っています。
アプリが起動したときにDLLを読み込み
継承クラスをインスタンス化したときに
領域が取られるわけですが、DLLのインスタンス部分の
サイズはDLLによって定義されるのではないかと考えている
ということです。

お礼日時:2009/05/24 09:47

DLLについてはこちらで詳細に解説されています。


http://msdn.microsoft.com/ja-jp/library/7h0a8139 …

MSDNにはWindows上での開発に関わる情報がたくさんあります。
わからないことがあったら、MSDNで調べてみましょう。

DLLですが、一般のアプリと変わりません。

あえて注意する点といいますと
常駐オブジェクトの扱いですね。

C++では良く"資源管理はコンストラクタ"と言われます。
コンストラクタ中でメモリを確保し、
デストラクタで廃棄するのがお決まりパターンとなっています。

しかし、この方法はDLL内のstaticオブジェクトには向かないようです。
(staticでなく、アプリが自分で構築する分には問題ない)
コンストラクタとは別の初期化関数を用意し、
アプリから明示的に呼ぶ方法が無難なようです。

特に、オブジェクトがスレッドを抱え込んでいて、
オブジェクトの生成と同時にスレッドも起動したい場合、
DLL内常駐オブジェクトでは絶対と言っていいほどできません。

各種常駐オブジェクトの初期化関数呼び出しを一個の関数に
まとめて"ライブラリ初期化関数"としてエクスポートし、

”DLLを使う際には、最初に初期化関数を呼んでね"

というお約束にしとく手をよく使います

(後始末も同様です)
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございます。
勉強になります。
> DLLですが、一般のアプリと変わりません。
アプリで定義した継承クラスを new した場合、
DLLで定義した基底クラスのインスタンスはDLLのデーター領域にでき、
アプリで定義した継承クラスの部分はアプリのデーター領域にできる・・?

お礼日時:2009/05/24 08:40

>仮に関数等ヘッダーで公開されている部分以外で


> DLLを更新した場合、インポートライブラリも
> 再リンクするような場面があるのでしょうか。

再リンクの必要はありません。

>DLL内に作成したクラスを継承することは不可能ですかね。
可能です。
実際、MFCユーザーはよくやっていることですよね。
MFCを"ダイナミック・リンク"して、
MFC内のCViewやCDialogから
アプリ側で派生クラスをこしらえるのは、
ごく普通にできていることです。

ただし、前提条件があります。
更新前と更新後で同一の処理系を使うことです。

C++は関数の多重定義を解決するため、
関数名に変更を加えます。
その変更方法は、
完全に(処理系の)デベロッパに委ねられており、
統一が図られていません。

A社の処理系で作成したDLLを利用して
アプリを作り
B社の処理系でビルドすることはできません。

DLLも含めて、全体を
B社の処理系で
リビルドすれば問題はなくなります
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

> 再リンクの必要はありません。
やはりそうなのですか。
バイナリエディタで開くと関数名しかないので
関数の定義をしているだけなのですね。

> 実際、MFCユーザーはよくやっていることですよね。
> MFCを"ダイナミック・リンク"して、
> MFC内のCViewやCDialogから
> アプリ側で派生クラスをこしらえるのは、
> ごく普通にできていることです。
そういえば・・
よろしければやり方をご教示いただけるとありがたいです。
気になるのはインスタンスの生成と開放の部分なのですが、
その他処理系の問題以外に注意しなければならないところなどあれば
お願いいたします。

お礼日時:2009/05/23 19:02

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QJavaでは多重継承ができない、の意味が分からない

「Javaでは多重継承ができない」「インターフェイスでは多重継承できる」の意味が分かりません。

「インターフェイス」の多重継承とは、あくまでも擬似多重継承であって、本当の多重継承とは機能が異なる、ということなのでしょうか?

それとも、多重継承はあくまでもクラスに対して行う言葉であり、それをインターフェイスで実現しているから、擬似なのでしょうか? つまり、機能としては完全に多重継承と同一?

あるいは、それ以外?

インターフェイスで可能なら、Javaで多重継承ができないという表現はおかしいように思うのですが…。

例えば、Javaのクラスでは多重継承できない、という言い方だと、また違った意味になるのでしょうか?

Aベストアンサー

Java で言う継承は extends で行われるものです。その意味で Java では多重継承ができません。
多重継承は慎重に慎重を重ねてクラス設計をしないと(いや、慎重に設計したとしても)問題を引き起こす可能性が大きいためです。
ではなぜインターフェースの implements で複数のインターフェースが指定可能かというと、インターフェースが問題を引き起こすものを持たないために複数指定可能だからです。

多重継承の問題点は簡単に言うと、以下のコードに現れます。
class A {
public void say() {
System.out.println("I'm A.");
}
}

class B {
public void say() {
System.out.println("I'm B.");
}
}

class C extends A, B {} // こんな書き方はできないが、説明のため

// ------------ コードのどこかで
C c = new C();
c.say(); // さて、なんて出力しよう?

上記の例では say() の実装が C では A と B の両方からもたらされるため、どちらを採用すればいいのかわからなくなっています。
後だしのほうの実装を採用すればいい(あるいはその逆)? では A と B に複数のメソッドがあって A の一部と B の一部の両方を使いたい場合はどう解決します?
(さらにさかのぼって言えば、A, B に共通の親クラス C0 があって、
C0 c0 = new C();
c0.say(); // さて、なんて出力しよう?
という場合のほうが深刻なのですが。
https://ja.wikipedia.org/wiki/%E8%8F%B1%E5%BD%A2%E7%B6%99%E6%89%BF%E5%95%8F%E9%A1%8C


上記の例を見れば解ると思うのですが、最初に述べた「(多重継承で)問題を引き起こすもの」というのは実装にかかわるもの(メソッド実装、インスタンス変数)のことです。インターフェースはこれらを持てないため、複数のインターフェースを implememts できます。

Java で言う継承は extends で行われるものです。その意味で Java では多重継承ができません。
多重継承は慎重に慎重を重ねてクラス設計をしないと(いや、慎重に設計したとしても)問題を引き起こす可能性が大きいためです。
ではなぜインターフェースの implements で複数のインターフェースが指定可能かというと、インターフェースが問題を引き起こすものを持たないために複数指定可能だからです。

多重継承の問題点は簡単に言うと、以下のコードに現れます。
class A {
public void say() {
System.out.print...続きを読む

QDLLの暗黙リンクの調べ方

http://hpcgi1.nifty.com/MADIA/Vcbbs/wwwlng.cgi?print+200511/05110055.txt

上記サイトと同じような現象で、loadlibraryが失敗してしまうのですが、「暗黙リンク」っていうものはどう調べたら良いのでしょうか?
フルパスにしてもDLLの読込で失敗してしまって困っております。
ちなみに環境は以下の通りです。
WindowsXP
VC++ 6.0

まだ初心者なので出来るだけ細かくお願いいたしますm(__)m

Aベストアンサー

LoardLibraryしているのに暗黙リンク?

リンクしているDLLがまた別のDLLをリンクしてるケースがあるかも。
VC++6.0に確か付属していた Dependency Walker を使えば暗黙リンクしている
DLLは確認できます。
動的リンクしているものはソースから調べてください。
(LoadLibraryの引数となっているパスのDLLもDependency Walkerで調べる対象)

Qパズドラで、転生シヴァにミューズのブルークレスト(エンハンス)を継承させたのですが、友達に意味わかん

パズドラで、転生シヴァにミューズのブルークレスト(エンハンス)を継承させたのですが、友達に意味わかんねぇ使い方すんなよって言われました。意味無い使い方なんですかねぇ、2ターンエンハンスなので強いと思ったのですが…

Aベストアンサー

ミューズは神タイプさえ付いてるなら大抵誰に継承しても活躍しますよ!

あえて言うなら、転生シヴァのサブは神染めではなく火染めを意識することが多いでしょうから、タイプエンハンスよりも属性エンハンスの方が使いやすい……といったところでしょうか。

あっ!でもシヴァドラと組むなら神染めになるかっ!

とにかくシヴァへの継承としては正解ですからご心配なく!!

Q継承したクラスを、継承元のクラス型の引数に渡すとどうなるのでしょうか?

継承したクラスを、継承元のクラス型の引数に渡すとどうなるのでしょうか?

以下のようなケースで、

#include "stdio.h"
using namespace std;

// baseクラス
class base {
private:
 int m_nII;
 int m_nJJ;
 int m_nKK;
public:
 base(int i,int j,int k){ m_nII=i; m_nJJ=j; m_nKK=k; }
 int GetSum(){ return (m_nII+m_nJJ+m_nKK); }
};

// base 継承クラス
class hoge : public base {
public:
 hoge() : base(1,2,3){}
};

void func(base* obj){ // baseクラスを引数に取る関数
 printf("sum is %d\n", obj->GetSum());
}

// main
int main(){
 hoge objHoge;
 func((base*)&objHoge); // <-キャストして渡す
 return 0;
}

として、一応、gccでコンパイルは通り、実行結果も期待通りだったのですが、
このやり方で問題は無いのでしょうか?
(たとえば継承先のクラスが独自のメンバを持っていたりなどした場合、期待した結果にならないとか・・)

よろしくお願いします。

継承したクラスを、継承元のクラス型の引数に渡すとどうなるのでしょうか?

以下のようなケースで、

#include "stdio.h"
using namespace std;

// baseクラス
class base {
private:
 int m_nII;
 int m_nJJ;
 int m_nKK;
public:
 base(int i,int j,int k){ m_nII=i; m_nJJ=j; m_nKK=k; }
 int GetSum(){ return (m_nII+m_nJJ+m_nKK); }
};

// base 継承クラス
class hoge : public base {
public:
 hoge() : base(1,2,3){}
};

void func(base* obj){ // baseクラスを引数に取る関数
 printf("sum is...続きを読む

Aベストアンサー

言語仕様通りで問題ありません。

実行時の挙動の話をすると、
1.プログラムは関数と変数に分けられてメモリ上に配置される
プログラムがメモリにロードされて命令が実行される段階では、プログラムはテキスト領域、静的領域、ヒープ領域、スタック領域に分けられて実行されます。
テキスト領域には、関数が機械語に翻訳された内容が格納されますので、このことからメンバ関数を増やしても問題になりません。

2.メンバ変数は基底(継承元)クラスのメンバの後に継承クラスのメンバが継ぎ足しされる。

hoge のインスタンス(obj)のメモリ上の配置
1000から1019のアドレスにobjは格納される。
1000から1011のアドレスにobjのbaseクラスのメンバが格納される。
1012から1019のアドレスにobjのhogeクラスのメンバが格納される。
1000: base.m_nII; // base クラスのメンバ変数(obj)
1004: base.m_nJJ; // 〃
1008: base.m_nKK; // 〃
1012: hoge.m_anpan; // hoge クラスで追加したメンバ変数
1016: hoge.m_pizza; // 〃

3.メンバ関数は、構造体へのポインタを受け取る関数
「func」関数の引数で「base *obj」を指定し「obj->GetSum()」と呼び出すことは
「static int base::GetSum(base *obj)」の呼び出しと同じである。
つまり、構造体へのポインタを引数とする関数に等しい。

// 以上のことをC言語に直すとこんな風になります。
struct base { int m_nII, m_nJJ, m_nKK; };
struct hoge { struct base base; int m_anpan, m_pizza; };

void base_init(struct base *obj, int i, int j int k)
{ obj->m_nII = i; obj->m_nJJ = j; obj->m_nKK = k; }
int base_GetSum(struct base *obj)
{ return obj->m_nII + obj->m_nJJ + obj->m_nKK; }

void hoge_init(struct hoge *obj)
{ base_init((struct base *)obj, 1, 2, 3); obj->m_anpan = 120; obj->m_pizza = 3000; }
int hoge_GetPizza(struct hoge *obj)
{ return obj->m_pizza; }

int main() {
struct hoge obj; hoge_init(&obj);

printf("sum is %d\n", base_GetSum((struct base *)&obj));

obj.m_anpan = 1200;
printf("Anapn is \\%d\n", obj.m_anpan);
printf("Pizza is \\%d\n", hoge_GetPizza(&obj));

// アドレス表示
printf("obj.base.m_II : %x\n" &obj.base.m_II);
printf("obj.base.m_JJ : %x\n" &obj.base.m_JJ);
printf("obj.base.m_KK : %x\n" &obj.base.m_KK);
printf("obj.m_anpan : %x\n" &obj.m_anpan);
printf("obj.m_pizza : %x\n" &obj.m_pizza);

return 0;
}

ポイントは、クラスという概念は関数と構造体を一体的に扱う仕組みであり言語仕様上にのみ存在し、実行時にメンバ関数は単純な引数渡しと関数呼び出しになるということです。

関連として、関数のオーバーライド、ポリモルフィズムなどがありますが、それの実体は構造体のレコードに関数ポインタ配列へのポインタを持たせているだけです。
つまり理解するには、C言語の関数ポインタ、関数ポインタの配列について理解することが、遠回りですが近道になります。
# 理解しなくても使うことはできますが(ーー;)

あと、コードっぽいのは適当に書いただけなので間違いがあると思います。

参考URL:http://brain.cc.kogakuin.ac.jp/~kanamaru/lecture/MP/final/part06/node8.html

言語仕様通りで問題ありません。

実行時の挙動の話をすると、
1.プログラムは関数と変数に分けられてメモリ上に配置される
プログラムがメモリにロードされて命令が実行される段階では、プログラムはテキスト領域、静的領域、ヒープ領域、スタック領域に分けられて実行されます。
テキスト領域には、関数が機械語に翻訳された内容が格納されますので、このことからメンバ関数を増やしても問題になりません。

2.メンバ変数は基底(継承元)クラスのメンバの後に継承クラスのメンバが継ぎ足しされる。

hoge ...続きを読む

Q継承とsuperの意味が理解できません。

継承とsuperの意味が理解できません。

今日は、JAVA初心者です、宜しくお願いします。
1番目のアプレットで「Applet」を継承させると、正常にWINDOWが表示されます。
しかし、2番目のアプリケ-ションを動かすと、「JFrame」を継承して、「PAINT」
を上書きしているのに、WINDOWは表示されますが、
透明になって、下側の画面が映り、Todayという文字は正常に表示されません。
paintメソッド内に、「super.paint(g);」を書いてやると、正常に動作します。
(3番目のプログラム)

テキスト通に、「JFrame」を継承して、「PAINT」を上書きしているのに、「PAINT」
メソッド内で、更に「super.paint(g);」を呼び出す必要性、理由がわかりません。
継承の意味が無いと思うのですが、他に原因があるのでしょうか。
継承している子クラスは、無条件で親クラスのメソッドを上書き出来ると思うのですが、
一体どのような時にSUPERが必要になるのでしょうか。
宜しくお願いします。

1番目のプログラムをと2番目のプログラムはアプレット、アプリケーションとの違い
はあるとしても、 基本的な考え方は違わないと考えてるのですが。

======================================================
public class Sample1 extends Applet
{
public void paint(Graphics g)
{
g.drawString("java",10,10);
}
}
======================================================
public class JFrameTest extends JFrame
{
JFrameTest()
{
setSize(400,300);
setTitle("JFrameTest");
}

public void paint(Graphics g)
{
g.drawString("Today",100,100);
}

public static void main(String[] args)
{
JFrame jf = new JFrameTest();
jf.show();
}
}
======================================================
public class JFrameTest extends JFrame
{
JFrameTest()
{
setSize(400,300);
setTitle("JFrameTest");
}

public void paint(Graphics g)
{
super.paint(g);
g.drawString("Today",100,100);
}

public static void main(String[] args)
{
JFrame jf = new JFrameTest();
jf.show();
}
}
======================================================

継承とsuperの意味が理解できません。

今日は、JAVA初心者です、宜しくお願いします。
1番目のアプレットで「Applet」を継承させると、正常にWINDOWが表示されます。
しかし、2番目のアプリケ-ションを動かすと、「JFrame」を継承して、「PAINT」
を上書きしているのに、WINDOWは表示されますが、
透明になって、下側の画面が映り、Todayという文字は正常に表示されません。
paintメソッド内に、「super.paint(g);」を書いてやると、正常に動作します。
(3番目のプログラム)

テキスト通に、「JFram...続きを読む

Aベストアンサー

私は .NET 使いなので Java は疎いのですが、
メソッドをオーバーロードして望み通りの結果が得られないという事は、親クラスの paint メソッド内で何か必要な処理をしているという事です。それを上書きしてしまうとその処理が呼び出されなくなる為動かなくなっているのでしょう。

JFrame の paint は下記にあるように
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/JFrame.html
java.awt.Container 由来のようなので、そちらを見てみると、super.paint(g) を呼べ、と書いてありますね。
http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/awt/Container.html#paint%28java.awt.Graphics%29

QUnix上C++でのdllとインポートライブラリの関係

こんにちわ。
いつも教えてgooにお世話になっているorange_pieです。
UNIX上のC++で作成した自作ライブラリをdllにして配布したいのですが、
Unixでの基本的な考え方を教えてください。

(1)Unix上ではDLLの標準的な名称は”libxxxx.so”とするのが普通ですか?
 ※この形式ならLD_LIBRARY_PATH環境変数が検索してくれる。。。
(2)通常、DLLにする場合、インポートライブラリ(.lib)と実際のライブラリ(.so)を作成して、使用する側はインポートライブラリのみをリンクするのでしょうか?
(3)配布されたdllを使う側では、Link時にインポートライブラリをリンクして、関連インクルードファイルをインクルードするだけで使えるのでしょうか?
(4)上記の(2)のように、インポートライブラリとライブラリの実態を作成する為のコンパイルオプションが見つかりません。(ldのmanを見たのですが、意味がわからないと言うか。。。。。)

この質問は、自作ライブラリからlibxxx.soという形のオブジェクトファイルを作り、別プログラムからこのlibxxxをコンパイルオプション(-l)でリンクしてみたら正しく動作したのですが、これでは結局ライブラリの本体が一緒にリンクされている様子で、出来上がった実行形式のファイルサイズが静的ライブラリとしてリンクした時と同じ大きさになっていることに疑問を抱いてしまったものです。
 この状態でも、ライブラリの方だけコンパイルしなおして実行すると
ちゃんとライブラリの変更点は反映されるので問題は無いのですが、
これでもダイナミックリンク・ライブラリと呼べるのでしょうか?

こんにちわ。
いつも教えてgooにお世話になっているorange_pieです。
UNIX上のC++で作成した自作ライブラリをdllにして配布したいのですが、
Unixでの基本的な考え方を教えてください。

(1)Unix上ではDLLの標準的な名称は”libxxxx.so”とするのが普通ですか?
 ※この形式ならLD_LIBRARY_PATH環境変数が検索してくれる。。。
(2)通常、DLLにする場合、インポートライブラリ(.lib)と実際のライブラリ(.so)を作成して、使用する側はインポートライブラリのみをリンクするのでしょうか?
(3)配布されたdll...続きを読む

Aベストアンサー

# すっごく暇ってわけではないんですが :-)

> -Wl,-B,dynamic -lclntsh -ldl -lm -lnsl -lsocket -lrt -lpthread
>
> この中の”-B, dynamic ”の辺りが「ライブラリをダイナミックにリンクするよ」ってことだったのでしょうか?

man ld の -l と -B のところを読めば分かると思いますが、大体、そういうことです。

-B dynamic の場合(普通は、こっちがデフォルト)には -lxxx の指定で libxxx.so
を探して、無ければ、libxxx.a を探します。-B static の場合には libxxx.so を
対象にしません。

参考URLには solaris の AnswerBook を紹介しておきます。


> ということも考慮に入れると、arコマンドで作ったアーカイブもDLLもリンクオプションで-B dynamic とすれば、実行時にリンクできる。(のかな?)

いやいや。静的なライブラリ、っつう位ですから、静的なリンクにしか使え
ません。

.a も .so も「ライブラリ」って名前がつきますけれど、.a はアーカイブファイル
なので、tar の出力ファイルの方に似ています。.so の方は、実行形式のヘッダを
持ち ELF というフォーマットのファイルで実行バイナリの方に似ています。


> で、他人に提供するのにアーカイブとDLLのどちらが適しているかというと、
> 関数などが増えた場合以外はどちらでも同じ(という感じ?なのかな?)

その「他人」の環境次第なんですが、相手の OS やバージョンが特定できないと
静的なアーカイブの方が、利用できる可能性が少し広いです(ソース提供には
遠く及ばないですが)。

> arコマンドは、複数のオブジェクト(.o)を追加することで作成しなおすことができるが、DLLはライブラリ構成プログラムをリコンパイルする必要がある。

リコンパイルではなく、再リンクです。


後、共有ライブラリの場合には、あまり小さく刻んでしまうとロードの時間が
気になり出すので、ひとつのファイルの単位をどうするかを悩むときがあり
ます。


最後に、No.2 の回答にあるように unix をひと括りにして、.so が普通、と
言うのは、ちょっと大雑把すぎました。他の質問のことが頭にあったもので
orange_pie さんが使っている環境を暗に想定してました。

十年くらいさかのぼっただけで共有ライブラリが扱えない unix なんてのは、
ごろごろしてましたし。

参考URL:http://docs.sun.com:80/ab2/coll.153.4/REFMAN1/@Ab2PageView/116238?Ab2Lang=ja&Ab2Enc=shift_jis

# すっごく暇ってわけではないんですが :-)

> -Wl,-B,dynamic -lclntsh -ldl -lm -lnsl -lsocket -lrt -lpthread
>
> この中の”-B, dynamic ”の辺りが「ライブラリをダイナミックにリンクするよ」ってことだったのでしょうか?

man ld の -l と -B のところを読めば分かると思いますが、大体、そういうことです。

-B dynamic の場合(普通は、こっちがデフォルト)には -lxxx の指定で libxxx.so
を探して、無ければ、libxxx.a を探します。-B static の場合には libxxx.so を
対象にしません。...続きを読む

Qインタフェース、クラスの継承、コンストラクタ意味

Javaを学習している初心者です。

インタフェース、コンストラクタ、クラスの継承について、
必要な理由が、イマイチよく分かりません。

特に設定しなくても、プログラムは動くと思うのですが・・・
(特にインタフェース)

詳しい方、教えて下さい。

Aベストアンサー

単純な例題などでは必要性を感じないでしょうね。実際不要だし…
しかし、プロジェクトが複数で、パッケージが200~300、ソースが
2000以上などと言う規模になると、必要になってきます。

コンストラクタ
早い話がクラスの初期設定です。不要なら空の記述でかまいません。
ただ、面白い使い方があります。コンストラクタの属性をprivate、
あるいは「無し」にします。前者は特定の方法でしかインスタンスを
作れないようにする、後者は同一パッケージ内でのみインスタンスを
作れるようにする場合です。プロジェクトが大きく、これに携わる
プログラマの技量にバラつきがある場合、不要な混乱を避けるという
効果があります。また、マルチスレッドで、クリティカルな制御を
する場合(複数の処理スレッドが同時に実行された時に混乱しない
ようにするための制御)などに使います。

インターフェース
これは分かり難い。事実、技量不足のプログラマに作らせると、
とんでもないバグの原因になったりしますので、使い方も難しい。
例え話:会社の支店を考えましょう。支店には必ず支店長、住所が
あるものとします。しかし、新宿支店には特設会場があり、渋谷支店
には保養所がある。この状態で支店住所を処理するプログラムがある
とすると、支店が新宿なら…、渋谷なら…、○○なら…というように
しなければなりませんね。でも、各支店が支店インターフェースを
持ち、これに支店長と住所があると記載されていれば、プログラムは
「支店の住所」とするだけで良いのです。
同様の使い方をするものに抽象クラスというものがあります。
個人的にはこちらの方が好みです。間違いが少ないし、手続実体を
記述することができます。

継承
機能A、B、Cを持つクラスXがあるとします。仕様が変更になり、
機能Dを追加したとします。直接、Xを修正しても良いのですが、
既存機能A、B、Cが影響を受けていないかどうかを再テストする
必要があります。しかし、Xを継承したクラスYを作り、ここには
機能Dだけを記述します。この場合は機能Dのテストだけで十分と
言えます。(作り方がマズイと継承元の機能に影響することもある)
クラスYはXを継承しているので、機能A、B、Cを持っています。
また、ある共通機能を持つクラスを独立させておくと、これを使う
場合、このクラスをインスタンス化する必要がありますが、この
クラスを継承すると、インスタンス化する必要はなく、自身の
メソッドを呼ぶのと全く同じ感覚で実行することができます。
他にも継承の恩恵は数多くありますが、長くなるので、この辺で
止めます。

と、まぁ文章で語るとこんな具合で、どうしても抽象概念しか分かり
ませんよね。感覚的に「こういうもんだ」と分かるには実経験を
積んで、いろいろな場面に遭遇するしかないでしょうね。

単純な例題などでは必要性を感じないでしょうね。実際不要だし…
しかし、プロジェクトが複数で、パッケージが200~300、ソースが
2000以上などと言う規模になると、必要になってきます。

コンストラクタ
早い話がクラスの初期設定です。不要なら空の記述でかまいません。
ただ、面白い使い方があります。コンストラクタの属性をprivate、
あるいは「無し」にします。前者は特定の方法でしかインスタンスを
作れないようにする、後者は同一パッケージ内でのみインスタンスを
作れるようにする場合です。...続きを読む

QDLLファイルの暗黙的リンクについて

環境:WindowsXP VC2005

OpenSSLのRSA構造体を暗黙的リンクしようとしているのですが、
やり方がわかりません。

OpenSSLの関数群で、RSA構造体が使用されているのですが、
RSA構造体をdllimport出来ないので、失敗してしまいます。

[フォーマット]
(例)main.c

int main(void)
{
__declspec(dllimport) RSA* 関数名(引数);

※RSA構造体をdllimportしていないため、エラーが発生。
}

構造体をdllimportする方法をご存知の方がいらっしゃいましたら、
お願いします。

Aベストアンサー

>※RSA構造体をdllimportしていないため、エラーが発生。
という解釈が間違っています。

未定義のユーザ定義型※1を使用したためのコンパイルエラーがエラー原因だと思われます。
※1ユーザ定義型とは、typedefで宣言した型のこと。「ワシの知らんデータ型を使っちょるが、typedef宣言が見当たらんぞ!!」とコンパイラ親爺がお怒りです。

解決方法ですが、
本当にopensslライブラリを利用するつもりなら、
ssl.hヘッダファイルを#include宣言して下さい。

RSAユーザ定義型は、ssl.hヘッダファイル中、
 typedef struct rsa_st RSA;
と宣言されています。

なお、コンパイラを誤魔化すだけなら、他の手段もあります。
しかし、opensslライブラリを利用するなら、#include宣言が必須。


最後に、今後の勉強も兼ねて、解釈の誤りを指摘します。
誤り1.
"RSA*"は、RSAユーザ定義型のポインタ型です。RSA構造体のポインタ型ではありません。
RSA構造体のポインタ型は、あえて記述すると"struct RSA*" です。実際は、"struct rsa_st"なのでハズレですが。

誤り2.
データ型定義(や構造体定義)は、#include宣言 じゃないと、インポートできません。
dllimport宣言ができるのは、DLLから関数ポインタを取得することだけです。

>※RSA構造体をdllimportしていないため、エラーが発生。
という解釈が間違っています。

未定義のユーザ定義型※1を使用したためのコンパイルエラーがエラー原因だと思われます。
※1ユーザ定義型とは、typedefで宣言した型のこと。「ワシの知らんデータ型を使っちょるが、typedef宣言が見当たらんぞ!!」とコンパイラ親爺がお怒りです。

解決方法ですが、
本当にopensslライブラリを利用するつもりなら、
ssl.hヘッダファイルを#include宣言して下さい。

RSAユーザ定義型は、ssl.hヘッダファイル中、...続きを読む

Qprivate継承はどう使う?

C++の話です

class Base{.....};
class Derived1 : public Base{.....};
class Derived2 : private Base{.....};

と書くことができますが、public継承とprivate継承にはそれぞれ意味がありますよね。
public継承は"is-a"関係を意味していて、private継承は
"is-implemented-in-terms-of"関係を表していると言います。
public継承を実際に動くプログラムは思いつくのですが、private継承を使ったプログラムが思いつきません(というより有効に使えません)

派生クラスから呼び出せない、外部からも呼び出せないメンバをどう使うのでしょうか?

Aベストアンサー

> 基底クラスの段階でのprivateと継承してからの段階でprivate
> 扱いになるのとでは意味が違うのでしょうか?

継承時のアクセス制限は、いうなれば「継承する側の都合」なので、
「継承する自分自身を"呼ぶクラス"や自分自身より"下位の派生クラス"」に影響します。
privateで継承したクラス自身はこの影響を受けずに、
自分自身は基底クラスの方の影響だけを受けるということです。

定義も派生する側に書きますよね。
同じ基底クラスからでも継承するクラス毎に別設定できるということです。
# なので、他のクラスの一部実装だけを流用するためにprivateで実装継承なんてこともありえるのです。
# publicで継承すると余計なインターフェイスまで取り込んじゃいますが、
# privateなら内部で利用するだけですから余分なものがあっても自分が使うだけで、外には漏らしません。
# (private継承できない時/言語では、変わりに「委譲」することが多いです)
# (例えばJavaとかはサブクラス側で狭めることはできないですが、C++は必要に応じて選択肢が多い、と。(その分複雑ともいう))

一方、基底クラス側のアクセス制限は「規定クラスの都合」なので、
継承する自分自身も「基底クラスの外、より下位の派生」ですから、privateの影響を受けます。
これを勝手にサブクラスが変更することは、当然できません。

> 派生クラスから呼び出せない、外部からも呼び出せないメンバをどう使うのでしょうか?

本題に戻ると、private継承であれば継承したクラス自身は(自分だけ)使えますし、
privateなメンバであれば自分だけは使えますので、自分専用の内部実装を書くのが基本かと。

# ちなみに、C++のprivate:はあくまで「クラスの"呼び出し制限"」なので、例えばこんなことも可能。

/** 純粋仮想関数を含む基底クラス */
class Foo {
private:
 /** 内部実装はサブクラスに要請 */
 virtual void doSomething() = 0; /* 呼び出しはprivateなのに実装は純粋仮想 */
public:
 /** 外部インターフェイスは持つ */
 void do(){ doSomething(); } /* このクラス内からしか呼べないようにdoSomethingはprivate */
}
/* 継承したサブクラスは、Foo::doSomethingを呼べないのに実装は定義しなければならない */

> 基底クラスの段階でのprivateと継承してからの段階でprivate
> 扱いになるのとでは意味が違うのでしょうか?

継承時のアクセス制限は、いうなれば「継承する側の都合」なので、
「継承する自分自身を"呼ぶクラス"や自分自身より"下位の派生クラス"」に影響します。
privateで継承したクラス自身はこの影響を受けずに、
自分自身は基底クラスの方の影響だけを受けるということです。

定義も派生する側に書きますよね。
同じ基底クラスからでも継承するクラス毎に別設定できるということです。
# なの...続きを読む

QVC++2008でインポートライブラリのスタティックリンクの設定

VC++2008でインポートライブラリのスタティックリンクの設定
従来のVC++6.0ではプロジェクトのビルド時にインポートライブラリをスタティックリンクさせる場合
「プロジェクト」メニューから「設定」項目を選択し、「プロジェクトの設定」ウィンドウを表示させて、
「リンク」タブをクリックして表示されるページの「オブジェクト/ライブラリモジュール」欄の先頭に、
MyDll.lib(例)とスペースを1つ入力していました。末尾のスペースはMyDll.libとkernel32.libを区切るために必要でした。

これをVC++2008で実現するためにはどの様にしたらいいのですか?
VC++2008の「プロジェクト」メニューを探しても「プロジェクトの設定」ウィンドウがありません。

Aベストアンサー

VC++.NET 2003で確認しましたが、2005でも同様だったので、2008でも変わらないと思います。

(1)「プロジェクト」メニューから「○○○のプロパティ」(○○○はプロジェクト名)を選択。
(2)「構成プロパティ」の「リンカ」の「全般」を選択。
(3)「追加のライブラリディレクトリ」に該当のディレクトリを設定。
(4)「構成プロパティ」の「リンカ」の「入力」を選択。
(5)「追加の依存ファイル」に該当のライブラリファイルを設定。

(3)、(5)は「構成」(Debug、Release等)や「プラットフォーム」(Win32等)の必要なものすべてに付いて行います。


人気Q&Aランキング

おすすめ情報