我有一个构造函数,其中我想传递前2个参数: ID3D11ShaderResourceView * 作为稳定下载的纹理 OR const CHAR * 作为文件下载这个纹理并将其分配给类ID3D11ShaderResourceView *成员(按需发布以下版本),但我无法理解我应该如何正确地做到这一点。它看起来像这样:
class {button
public
button() {};
button(data1 (or texture or filname), data2 (or texture or filname), rest data....);
...
~button();
}
所以我试过了:
我不想重载构造函数,因为这将创建其中4个,它们几乎不同。你认为boost :: variant在这种情况下对我有帮助吗?是否有任何平滑有效的方法来构建这种构造函数?我的c ++知识是初级的,对不起,如果它是一个重复的主题,在创建它的同时阅读它给我的建议,但似乎没有发现任何类似的东西,谢谢:)
更新 应用boost :: any,得到下一个结果:
class button : public frame {
public:
button() {};
button(boost::any _texture,
boost::any _hover_texture,
...
};
if (_texture.type() == typeid(ID3D11ShaderResourceView*)) texture = boost::any_cast<ID3D11ShaderResourceView*>(_texture);
if (_texture.type() == typeid(const char*))
{
if ( FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice,boost::any_cast<const char*>(_texture), NULL, NULL, &texture, NULL )) )
mboxout( "loading texture failed.", "UI texture load error", true );
};
if (_hover_texture.type() == typeid(ID3D11ShaderResourceView*)) hover_texture = boost::any_cast<ID3D11ShaderResourceView*>(_hover_texture);
if (_hover_texture.type() == typeid(const char*))
{
if ( FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice, boost::any_cast<const char*>(_hover_texture), NULL, NULL, &hover_texture, NULL )) )
mboxout( "loading texture failed.", "UI texture load error", true );
};
这是唯一可能的决定,因为这对我来说似乎很尴尬吗?谢谢:))
答案 0 :(得分:0)
As always, when you have combinatoric explosion/tedious repetition, refactor your code into reusable units.
In this case, your constructor could be just
template <typename T1, typename T2>
button(T1 const& texture, T2 const& hover_texture)
: _texture(load(texture)),
_hover_texture(load(hover_texture))
{
};
And all the loading logic would be inside... you guess it the load
function. A sample implementation of that:
static ID3D11ShaderResourceView* load(ID3D11ShaderResourceView* v){
return v; // just return the resources passed in
}
static ID3D11ShaderResourceView* load(char const* fname) {
ID3D11ShaderResourceView* p = NULL;
if (FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice, fname, NULL, NULL, &p, NULL)))
throw std::runtime_error(std::string("loading texture failed (") + fname + ")");
return p;
}
Note: while we were at it we separated UI from business logic. You do not want to display messageboxes from inside constructors. Ever. You just want to notify the caller of the problem and the caller decides what to do (use another resource, try a different path, retry a download, write a warning message to the log, shut down etc.)
#include <iostream>
#include <stdexcept>
///////////////////////////////////////////////////////
// mocking ID3D*
struct ID3D11ShaderResourceView;
enum ERROR_CODE { ERR_OK };
#define FAILED(e) (ERR_OK != (e))
static int gvDevice = 42;
ERROR_CODE D3DX11CreateShaderResourceViewFromFile(int, char const* fname, void*, void*, ID3D11ShaderResourceView**, void*) {
std::cout << "Loaded from " << fname << "\n";
return ERR_OK;
}
//
///////////////////////////////////////////////////////
struct frame{ virtual ~frame() = default; };
class button : public frame {
public:
button() {};
template <typename T1, typename T2>
button(T1 const& texture, T2 const& hover_texture)
: _texture(load(texture)),
_hover_texture(load(hover_texture))
{
};
private:
// TODO Rule-Of-Three constructor/destructorl
// SUGGEST: Rule-Of-Zero using shared pointers instead
ID3D11ShaderResourceView* _texture;
ID3D11ShaderResourceView* _hover_texture;
static ID3D11ShaderResourceView* load(ID3D11ShaderResourceView* v) { return v; }
static ID3D11ShaderResourceView* load(char const* fname) {
ID3D11ShaderResourceView* p = NULL;
if (FAILED(D3DX11CreateShaderResourceViewFromFile(gvDevice, fname, NULL, NULL, &p, NULL)))
throw std::runtime_error(std::string("loading texture failed (") + fname + ")");
return p;
}
};
#include <cassert>
int main() {
ID3D11ShaderResourceView* default_texture = NULL;
assert(!FAILED( D3DX11CreateShaderResourceViewFromFile(gvDevice, "default_texture.bin", NULL, NULL, &default_texture, NULL)));
try {
button button1("t1.bin", "hover1.bin");
button button2(default_texture, "hover2.bin");
button button3("t3.bin", default_texture);
button button4(default_texture, default_texture);
} catch(std::exception const& e) {
std::cout << "Oops: " << e.what() << "\n";
}
}
Prints:
Loaded from default_texture.bin
Loaded from t1.bin
Loaded from hover1.bin
Loaded from hover2.bin
Loaded from t3.bin
There's still a lot to be improved (see the comments, e.g.) but this is a start.