【发布时间】:2022-03-30 17:14:09
【问题描述】:
抱歉,这可能看起来很简单,但有人问过我这个问题,我不确定。
一个空的C++类有什么功能?
构造函数, 复制构造函数, 任务, 析构函数?
是这样吗?还是还有更多?
【问题讨论】:
-
现在在 3 次采访中被问到过。
标签: c++
抱歉,这可能看起来很简单,但有人问过我这个问题,我不确定。
一个空的C++类有什么功能?
构造函数, 复制构造函数, 任务, 析构函数?
是这样吗?还是还有更多?
【问题讨论】:
标签: c++
在C++03中有4个:
默认构造函数:仅在以下情况下声明 没有用户定义的构造函数 宣布。使用时定义
复制构造函数 - 仅在用户未声明时才声明。如果使用则定义
复制赋值运算符同上
析构函数同上
在 C++11 中还有两个:
编译器也可能无法生成其中的一些。例如,如果类包含例如引用(或任何其他无法复制分配的内容),则编译器将无法为您生成复制分配运算符。 For more information read this
【讨论】:
如果我定义以下类
class X
{};
编译器会定义以下方法:
X::X() {} // Default constructor. It takes zero arguments (hence default).
X::~X() {} // Destructor
X::X(X const& rhs) {}; // Copy constructor
X& operator=(X const& rhs)
{return *this;} // Assignment operator.
// Since C++11 we also define move operations
X::X(X&& rhs) {}; // Move Constructor
X& operator=(X&& rhs)
{return *this;} // Move Assignment
注意:
如果定义了 ANY 构造函数,则不会构建默认构造函数。
如果用户定义了替代方法,则不会构建其他方法。
更有趣的是当我们有成员和基时的默认实现:
class Y: public X
{
int a; // POD data
int* b; // POD (that also happens to be a pointer)
Z z; // A class
};
// Note: There are two variants of the default constructor.
// Both are used depending on context when the compiler defined version
// of the default constructor is used.
//
// One does `default initialization`
// One does `zero initialization`
// Objects are zero initialized when
// They are 'static storage duration'
// **OR** You use the braces when using the default constructor
Y::Y() // Zero initializer
: X() // Zero initializer
, a(0)
, b(0)
, z() // Zero initializer of Z called.
{}
// Objects are default initialized when
// They are 'automatic storage duration'
// **AND** don't use the braces when using the default constructor
Y::Y()
:X // Not legal syntax trying to portray default initialization of X (base class)
//,a // POD: uninitialized.
//,b // POD: uninitialized.
,z // Not legal syntax trying to portray default initialization of z (member)
{}
//
// Note: It is actually hard to correctly zero initialize a 'automatic storage duration'
// variable (because of the parsing problems it tends to end up a a function
// declaration). Thus in a function context member variables can have indeterminate
// values because of default initialization. Thus it is always good practice to
// to initialize all members of your class during construction (preferably in the
// initialization list).
//
// Note: This was defined this way so that the C++ is backward compatible with C.
// And obeys the rule of don't do more than you need too (because we want the C++
// code to be as fast and efficient as possible.
Y::Y(Y const& rhs)
:X(rhs) // Copy construct the base
,a(rhs.a) // Copy construct each member using the copy constructor.
,b(rhs.b) // NOTE: The order is explicitly defined
,z(rhs.z) // as the order of declaration in the class.
{}
Y& operator=(Y const& rhs)
{
X::operator=(rhs); // Use base copy assignment operator
a = rhs.a; // Use the copy assignment operator on each member.
b = rhs.b; // NOTE: The order is explicitly defined
z = rhs.z; // as the order of declaration in the class.
return(*this);
}
Y::~Y()
{
Your Code first
}
// Not legal code. Trying to show what happens.
: ~z()
, ~b() // Does nothing for pointers.
, ~a() // Does nothing for POD types
, ~X() ; // Base class destructed last.
// Move semantics:
Y::Y(Y&& rhs)
:X(std::move(rhs)) // Move construct the base
,a(std::move(rhs.a)) // Move construct each member using the copy constructor.
,b(std::move(rhs.b)) // NOTE: The order is explicitly defined
,z(std::move(rhs.z)) // as the order of declaration in the class.
{}
Y& operator=(Y&& rhs)
{
X::operator=(std::move(rhs)); // Use base move assignment operator
a = std::move(rhs.a); // Use the move assignment operator on each member.
b = std::move(rhs.b); // NOTE: The order is explicitly defined
z = std::move(rhs.z); // as the order of declaration in the class.
return(*this);
}
【讨论】:
(a=b).something(),那么是的,通过返回引用你可以做到这一点,但这绝对是一个非常糟糕的做法。另外请注意,通过返回常量引用,您仍然可以调用常量方法。
只是为了扩展Armen Tsirunyan answer,这里是方法的签名:
// C++03
MyClass(); // Default constructor
MyClass(const MyClass& other); // Copy constructor
MyClass& operator=(const MyClass& other); // Copy assignment operator
~MyClass(); // Destructor
// C++11 adds two more
MyClass(MyClass&& other) noexcept; // Move constructor
MyClass& operator=(MyClass&& other) noexcept; // Move assignment operator
【讨论】:
【讨论】:
是吗?
是的,就是这样。
编译器默认生成
一堂课
使用Clang的-ast-dump选项可以看到默认生成的构造函数、复制构造函数和赋值操作符
prasoon@prasoon-desktop ~ $ cat empty.cpp && clang++ -cc1 -ast-dump empty.cpp
class empty
{};
int main()
{
empty e;
empty e2 = e;
{
empty e3;
e3 = e;
}
}
typedef char *__builtin_va_list;
class empty {
class empty;
inline empty() throw(); //default c-tor
//copy c-tor
inline empty(empty const &) throw() (CompoundStmt 0xa0b1050 <empty.cpp:1:7>)
//assignment operator
inline empty &operator=(empty const &) throw() (CompoundStmt 0xa0b1590 <empty.cpp:1:7>
(ReturnStmt 0xa0b1578 <col:7>
(UnaryOperator 0xa0b1558 <col:7> 'class empty' prefix '*'
(CXXThisExpr 0xa0b1538 <col:7> 'class empty *' this))))
};
【讨论】:
X 的析构函数调用X 直接成员的析构函数,即X 直接基类的析构函数类,如果 X 是最派生类 (12.6.2) 的类型,则它的析构函数调用 X 的虚拟基类的析构函数。” (C++03 12.4/6)