X値のポインターを作成できるかどうか(そして、どのように作成できるか)を
知りたいのですが、このポインターにどのタイプを割り当てることができるかを知っているとしましょう。
たとえば、X値のポインター(もちろん、この値の名前は自由に変更できます)は、string、bool、およびカスタムクラスの変数を指すことができます。
8 に答える
通常、あなたが説明することは悪い考えです。
void*
作品の限界値のための作品。それはすべてのタイプの安全性を捨て、あなたがそれを追跡することを要求します。
ルート型の作成は一種の機能ですが、プリミティブ型では機能せず、かなり煩わしいものです。
Aは、これら3つのタイプ( 、、または)boost::variant< bool*, std::string*, MyClass* >
のいずれかへのポインターを含むことができる変数です。型の安全性を強制し、構文が煩わしくなる可能性があるため、使用するのはおそらく難しいでしょう。bool
std::string
MyClass
同様に、へのポインタはboost::variant< bool, std::string, MyClass >
あなたが望むものかもしれませんが、それはbool
あなたがだまされていない変数を指すことを可能にしません。
C ++ 11を完全にサポートしているため、union
任意の型を含めることができ、列挙型とともに、のようなことを実行できますboost::variant
。欠点として、これはあなたが指摘されているものを必要としますunion
。完全なC++11サポートの有無にかかわらず、ポインターの結合は妥当です。どちらの場合も、タイプを手動で追跡し、同期を維持する必要があります。
多くの質問と同様に、動機が重要であるため、あなたが本当に考える必要があるのは、「なぜ私はこれを尋ねるのか」です。あなたは正しい質問をしていないかもしれません。
今日は新しい表現を学んだので、「これはXY問題です」という表現を使用します。Xを実行したいので、解はYだと思うので、Yの実行方法を尋ねます。おそらく質問する必要があります。代わりにYを行う方法。車の前輪がパンクしているのを見つけて、整備士に話しかけるのと少し似ていますが、「パンクを修正するにはどうすればよいですか」ではなく、「ホイールナットを元に戻すにはどうすればよいですか」と尋ねるだけです。すべてのホイールナットを取り外して車が倒れた後、車が倒れることなくホイールを外せるようにするには、車の下にジャッキを置く必要があることに気づきましたか...
確かに、無効なポインタとユニオンがありますが、それは大したことではありません。ただし、ポインタが実際に何を指しているのかを知る必要があります。そうしないと、血まみれになります。
したがって、一般的に、C ++では、おそらくそうすべきではありません。
あなたがすべきことは、あなたの「もの」を別のオブジェクトで包むことです。それは、コンテンツが何であるかを知っていて、それを処理することができます。そうすれば、オブジェクトが何であるか、そしてそれをどのように使用するかについての状態を維持する他の何かがありません。
たとえば、次のようにすることができます。
class AnyThing
{
public:
virtual ~AnyThing();
virtual std::string ToString() = 0;
... // other things you want to do with your "things".
};
class IntThing: public AnyThing
{
private:
int value;
public:
virtual std::string ToString() { ... convert int to string ... }
};
class StringThing : public Anything
{
private:
std::string value;
public:
virtual std::string ToString() { return value; }
}
ポインタを使用して無効にすることができます。
void*
任意のデータ型を指すプロパティがあります。これは実際には、任意のデータ型の変数を配置してから関数に渡すコンテナーまたはキューブボードとしてvoid*
機能します。
使用するには、渡したデータのデータ型を知っている必要があります。
例えば:
int main()
{
int a;
void *x=&a;
func(x);
....
}
void func(void *argument)
{
int i=*(int *)argument;
....
}
これらの3つのタイプを指すためにのみ使用できるポインターが必要な場合は、次の3つのオプションが表示されます。
いくつかの基本クラスから派生するタイプごとにラッパークラスを作成します。
class Thingy { protected: Thing() {} }; class BoolThingy : public Thingy { bool x; } class StringThingy : public Thingy { String x; } class CustomThingy : public Thingy { Custom x; } ... Thingy *p = new BoolThingy;
スマートポインタクラスを作成し、、、、をとる代入演算子をオーバーロードし
bool *
、演算子もオーバーロードします(ただし、それが何をするのかはわかりません!)String *
Custom *
*
バリアントクラスを使用します(例
boost::variant
)。
しかし、どのオプションでも、そのようなものがどのように役立つかは明らかではありません...
任意の型(オブジェクト、ポインター、プリミティブ型など)へのポインターを持つことができますが、参照へのポインターを持つことはできません。
事前に型を知っていて、コンストラクターがない場合。次に、ユニオンを使用できます。
class CustomClass {};
union MyType
{
char const* a;
bool b;
float c;
};
MyType stuff;
MyType* ptrToStuff = &stuff;
int main()
{
ptrToStuff->a = "Plop";
ptrToStuff->b = false;
ptrToStuff->c = 12.0;
}
BoostにもANYタイプがあります。
あなたはそれに何でも保存することができます。
boost::any x = 12;
x = new CustomClass;
x = new std::string("Hi There");
x = std::string("Plop"); // even works without pointers.
いいえ、指定されていないタイプのオブジェクトを指すポインタを持つことはできません。ポインタの要点は、特定のタイプのオブジェクトを指すことです。int*x
を指す、int
をA*a
指すA
。
もちろん、あなたができることは、void*
何も指さないタイプの変数(void
)を持つことですが、任意のアドレスを保持することができます。どういうわけかそれがアドレスであるかを覚えているなら、あなたはstatic_cast<>
適切なポインタにキャストするためにを使うことができます。または、dynamic_cast<>
実行時void*
に特定のタイプを指しているかどうかを確認するために使用できます。これは次のように実装できます
struct AnyPointerWrapper
{
struct null_pointer {};
struct wrong_pointer_type {};
AnyPointerWrapper() : ptr(0) {}
AnyPointerWrapper(AnyPointerWrapper const&) = default;
AnyPointerWrapper&operator=(AnyPointerWrapper const&) = default;
template<typename T>
explicit AnyPointerWrapper(T*p)
: ptr(p) {}
template<typename T>
AnyPointerWrapper&operator=(T*p)
{ ptr=p; return*this; }
bool is_null() const
{ return ptr==0; }
template<typename T>
bool is() const
{ return dynamic_cast<T*>(ptr) != 0; }
template<typename T>
T* pointer()
{
if(p==0) throw null_pointer;
T*p = dynamic_cast<T*>(ptr);
if(p==0) throw wrong_pointer_type;
return p;
}
private:
void*ptr;
};
このように使用します
int X;
AnyPointerWrapper a;
assert(a.is_null());
a = &X;
assert(a.is<int>());
int*p = a.pointer<int>();
const
(ポインターのサポートを含む機能を追加できます)。ただし、これdynamic_cast<>
は些細なことではないことに注意してください。つまり、パフォーマンスが低下します。AnyPointerWrapper
これはポインタではないことにも注意してください。演算子を使用して、アドレスが;->
に格納されているオブジェクトのメンバー関数を呼び出すことはできません。AnyPointerWrapper::ptr
これは、適切なポインタを取得できる単なるラッパーです。