トップページ – Modern C++編 C++編](../../index.html) – 第15章
問題① 「RAII」の項のサンプルプログラムで、MyClassWrapperクラスは MyClass のオブジェクトを保持していますが「公開」されていないので、事実上使用できません。たとえば、次のような関数があると、MyClassWrapperクラスが保持している MyClass のオブジェクトが必要になります。
void f(const MyClass* mc);
MyClassWrapperクラスのオブジェクトを使いつつも、上記のような関数が利用できるように、MyClassWrapperクラスにメンバを補ってください。
単純な方法は、保持しているポインタ変数を返す「公開」されたメンバ関数を追加することです。
#include <iostream>
class MyClass {
public:
()
MyClass{
std::cout << "Constructor" << std::endl;
}
~MyClass()
{
std::cout << "Destructor" << std::endl;
}
};
class MyClassWrapper {
public:
() :
MyClassWrapper(new MyClass())
mObj{}
~MyClassWrapper()
{
delete mObj;
}
inline MyClass* Get()
{
return mObj;
}
private:
* const mObj;
MyClass};
void f(const MyClass* mc)
{
std::cout << "f()" << std::endl;
}
int main()
{
;
MyClassWrapper obj(obj.Get());
f}
実行結果:
Constructor
f()
Destructor
「非公開」のポインタ変数を「公開」してしまうことに怖さもありますが、単なるラッパークラスであると考えれば、そこまで厳格に考えなくても良いかもしれません。ただ、それを受け入れたとしても、使う際には「.Get()」のような余分な表記が必要になるため、やや不便ではあります。
もう1つの方法は、型変換演算子(第9章)を定義することです。
#include <iostream>
class MyClass {
public:
()
MyClass{
std::cout << "Constructor" << std::endl;
}
~MyClass()
{
std::cout << "Destructor" << std::endl;
}
};
class MyClassWrapper {
public:
() :
MyClassWrapper(new MyClass())
mObj{}
~MyClassWrapper()
{
delete mObj;
}
inline operator MyClass*()
{
return mObj;
}
private:
* const mObj;
MyClass};
void f(const MyClass* mc)
{
std::cout << "f()" << std::endl;
}
int main()
{
;
MyClassWrapper obj(obj);
f}
実行結果:
Constructor
f()
Destructor
この方法では利便性は高まりますが、意図せず起こる型変換が怖いところです。
いずれにしても、この例のように、delete演算子の呼び出しを自動化することが目的であれば、スマートポインタ📘を使った方が良いでしょう。
#include <iostream>
#include <memory>
class MyClass {
public:
()
MyClass{
std::cout << "Constructor" << std::endl;
}
~MyClass()
{
std::cout << "Destructor" << std::endl;
}
};
void f(const MyClass* mc)
{
std::cout << "f()" << std::endl;
}
int main()
{
std::unique_ptr<MyClass> obj(new MyClass());
(obj.get());
f}
実行結果:
Constructor
f()
Destructor
問題② RAII の考え方を使って、std::fopen関数に対する std::fclose関数を確実に行うクラスを設計してください。
コンストラクタ(他のメンバ関数でも構いません)でファイルをオープンして、デストラクタでクローズするようにします。std::FILE のポインタは、メンバ変数として保持しておきます。
#include <cstdio>
#include <iostream>
class MyClass {
public:
(const char* fname)
MyClass{
= std::fopen(fname, "r");
mFp }
~MyClass()
{
std::fclose(mFp);
}
private:
std::FILE* mFp;
};
int main()
{
("test.txt");
MyClass obj}
実行結果:
本来は、std::fopen関数を使わず、std::fstream などのファイルストリームを使うのが良いです。ファイルストリームについては、【標準ライブラリ】第13章で解説します。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |