在C ++中,我想将一个对象定义为类的成员:
Object myObject;
但是这样做会尝试调用它的无参数构造函数,它不存在。但是我需要在包含类进行一些初始化之后调用构造函数。这样的事情。
class Program
{
public:
Object myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject = Object(...);
}
}
答案 0 :(得分:23)
存储指向Object
而非实际Object
因此:
class Program
{
public:
Object* myObject; // Will not try to call the constructor or do any initializing
Program()
{
//Do initialization
myObject = new Object(...); // Initialised now
}
}
不要忘记在析构函数中delete
它。现代C ++可以帮助您,因为您可以使用 auto_ptr shared_ptr而不是原始内存指针。
答案 1 :(得分:15)
其他人已经使用原始指针发布了解决方案,但智能指针是一个更好的主意:
class MyClass {
std::unique_ptr<Object> pObj;
// use boost::scoped_ptr for older compilers; std::unique_ptr is a C++0x feature
public:
MyClass() {
// ...
pObj.reset(new Object(...));
pObj->foo();
}
// Don't need a destructor
};
这避免了添加析构函数的需要,并且隐式禁止复制(除非您编写自己的operator=
和MyClass(const MyClass &)
。
如果您想避免单独的堆分配,可以使用boost的aligned_storage
和placement new来完成。未测试的:
template<typename T>
class DelayedAlloc : boost::noncopyable {
boost::aligned_storage<sizeof(T)> storage;
bool valid;
public:
T &get() { assert(valid); return *(T *)storage.address(); }
const T &get() const { assert(valid); return *(const T *)storage.address(); }
DelayedAlloc() { valid = false; }
// Note: Variadic templates require C++0x support
template<typename Args...>
void construct(Args&&... args)
{
assert(!valid);
new(storage.address()) T(std::forward<Args>(args)...);
valid = true;
}
void destruct() {
assert(valid);
valid = false;
get().~T();
}
~DelayedAlloc() { if (valid) destruct(); }
};
class MyClass {
DelayedAlloc<Object> obj;
public:
MyClass() {
// ...
obj.construct(...);
obj.get().foo();
}
}
或者,如果Object
可以复制(或移动),则可以使用boost::optional
:
class MyClass {
boost::optional<Object> obj;
public:
MyClass() {
// ...
obj = Object(...);
obj->foo();
}
};
答案 2 :(得分:5)
如果您有权访问boost,则会提供一个名为boost::optional<>
的便捷对象 - 这样可以避免动态分配,例如
class foo
{
foo() // default std::string ctor is not called..
{
bar = boost::in_place<std::string>("foo"); // using in place construction (avoid temporary)
}
private:
boost::optional<std::string> bar;
};
答案 3 :(得分:4)
如果您可以将其他初始化移到构造函数中,您也可以重写代码以使用构造函数初始化列表:
class MyClass
{
MyObject myObject; // MyObject doesn't have a default constructor
public:
MyClass()
: /* Make sure that any other initialization needed goes before myObject in other initializers*/
, myObject(/*non-default parameters go here*/)
{
...
}
};
您需要注意,遵循这样的模式会引导您进入构造函数中执行大量工作的路径,这反过来导致需要掌握异常处理和安全性(作为返回错误的规范方法)从构造函数中抛出异常)。
答案 4 :(得分:0)
您可以使用指针(或智能指针)来执行此操作。如果不使用智能指针,请确保在删除对象时代码释放内存。如果您使用智能指针,请不要担心。
class Program
{
public:
Object * myObject;
Program():
myObject(new Object())
{
}
~Program()
{
delete myObject;
}
// WARNING: Create copy constructor and = operator to obey rule of three.
}
答案 5 :(得分:0)
你可以通过这个技巧完全控制对象的构造和破坏:
template<typename T>
struct DefferedObject
{
DefferedObject(){}
~DefferedObject(){ value.~T(); }
template<typename...TArgs>
void Construct(TArgs&&...args)
{
new (&value) T(std::forward<TArgs>(args)...);
}
public:
union
{
T value;
};
};
申请样品:
class Program
{
public:
DefferedObject<Object> myObject; //Should not try to call the constructor or do any initializing
Program()
{
...
//Now call the constructor
myObject.Construct(....);
}
}
这个解决方案的一大优点是,它不需要任何额外的分配,并且正常分配对象内存,但是在调用构造函数时你可以控制。
答案 6 :(得分:0)
这类似于jenkas的回答,但更直接
class Program
{
public:
union{
Object myObject;
}; //being a union member in this case prevents the compiler from attempting to call the (undefined) default constructor
Program()
{
...
//Now call the constructor
new (&myObject) Object(...);
}
~Program()
{
myobject.~Object(); //also make sure you explicitly call the object's destructor
}
}
无论如何,现在您必须显式定义所有特殊成员函数,因为编译器会默认将其删除。