1

次のようにメンバー変数を定義しました。変数は渡されないため、ここでは shared_ptr ではなく scoped_ptr を使用することにします。

class ClassName
{
public:
    ClassName() 
    {
        Initialize();
    }

    virtual void Initialize() = 0;

protected:
    boost::scoped_ptr<int> m_scpInt;
}

class ClassNameB : public ClassName
{
public:
    virtual void Initialize()
    {
        m_scpInt.reset(new int(100));
    }
}

scoped_ptr の制限により、後で変数の初期化を延期することにした場合、取得できる唯一のオプションはリセットを呼び出すことです。

Q1>これは良い習慣ですか?

Q2> それ以外の場合、より良い解決策はありますか?

ありがとうございました

/// 更新 -1 ///

これが私が本当にやりたいことです。

それぞれの派生クラスが Initialize という関数を定義し、その関数が InitializeVarA および InitializeVarB 関数を呼び出すように強制したいと考えています。ご指摘のとおり、コンストラクターで仮想関数を呼び出すことはできません。

class ClassName
{
public:
    ClassName() 
    {
    }       
    virtual void Initialize()
        {
            InitializeVarA();
            InitializeVarB();
        }           
    protected:
        virtual void InitializeVarA() {}
        virtual void InitializeVarB() {}
}

class ClassNameB : public ClassName
{
public:
    ClassNameB() 
    {
    }       
    virtual void Initialize()
        {
            InitializeVarA();
            InitializeVarB();
        }           
    protected:
        virtual void InitializeVarA() {}
        virtual void InitializeVarB() {}
}

ClassNameB cb;
cb.Initialize();

これよりも良い解決策はありますか?

4

1 に答える 1

4

これは良い習慣ですか?

resetスコープ付きポインターをリセットするために使用しても問題ありません。

基本クラスのコンストラクターから仮想関数を呼び出して派生クラスを初期化しようとすることは、単なる悪い習慣ではありません。それは間違っています。その時点で、オブジェクトの動的型は基本クラスであり、関数は純粋仮想であるため、それを呼び出すと未定義の動作が発生します。

非純粋にしても、その時点で派生クラスのオーバーライドを呼び出すことはできないため、ポインターはリセットされません。

それ以外の場合、より良い解決策はありますか?

基本クラスの直後に呼び出される派生クラスのコンストラクターでそれを行うことができます。

class Base {
public:
    Base() { /* don't call any virtual functions here */ }

protected:
    boost::scoped_ptr<int> p;
};

class Derived : public Base {
public:
    Derived() {
        p.reset(new int(100));
    }
};

または、割り当てられたメモリを基本クラスのコンストラクターに渡し、そこからポインターを初期化することもできます。ただし、これは少し危険です。例外がスローされたり、メモリがリークしたりする前に、ポインターをすぐに初期化する必要があります。

class Base {
public:
    Base(int * p) : p(p) {}

private: // doesn't need to be protected now
         // (unless something else in the derived class needs access)
    boost::scoped_ptr<int> p;
};

class Derived : public Base {
public:
    Derived() : Base(new int(100)) {}
};

C++11 では、unique_ptr移動可能な を使用して、リークのリスクを回避できます。

class Base {
public:
    typedef std::unique_ptr<int> ptr;
    Base(ptr && p) : p(p) {}

private:
    ptr p;
};

class Derived : public Base {
public:
    Derived() : Base(ptr(new int(100))) {}
};
于 2012-08-08T14:52:17.717 に答える