1. 面试题
有这样一个面试题:实现一个类,计算中程序中创建出了多少个类对象?
class Date {
public:
explicit Date(int year = 1900)
:_year(year)
{}
Date(const Date& d) {
_year = d._year;
}
private:
int _year;
};
Date fun(Date d) {
return d;
}
int main() {
Date d(2019); // 1 构造
fun(d); // 2 3 传值引发拷贝构造,构造出一个局部变量,返回值外部拷贝构造,共生成两个对象
system("pause");
return 0;
}
首先,调用函数发生一个拷贝构造出一个新的局部变量在函数栈帧中,该函数调用完之后,返回的不为d对象本身,函数调用完毕栈帧销毁,该局部变量不存在。所以为传值做返回,又引发一次值拷贝,拷贝构造出的新的对象返回到外部函数栈帧中。所以生成了两个对象。
class Date {
public:
explicit Date(int year = 1900)
:_year(year)
{
cout << "Date(int year)" << endl;
}
Date(const Date& d) {
_year = d._year;
cout << "Date(cosnt Date& d)" << endl;
}
Date& operator=(const Date& d) {
if (this != &d) {
_year = d._year;
}
cout << "operator=(const Date& d)" << endl;
return *this;
}
private:
int _year;
};
Date fun(Date d) {
return d;
}
int main() {
Date d(2019); // 1 构造
Date d2(2018); // 2 构造
Date d3 = d; // 3 拷贝构造
d2 = d; // 不会创建,赋值运算符重载
fun(d); // 4 5 传值拷贝构造 返回值拷贝构造
system("pause");
return 0;
}
class A {
public:
A() {++_scount;}
A(const A& t) {++_scount;}
static int GetACount() { return _scount;}
private:
static int _scount; // 静态成员
};
int Test::_count = 0;
void TestA() {
cout<<A::GetACount()<<endl;
A a1, a2;
A a3(a1);
cout<<A::GetACount()<<endl;
}
声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态的成员变量一定要在类外进行初始化。
2. 特性
1)静态成员为所有类对象所共享,不属于某个具体的实例。普通成员属于对象,可以理解为静态成员属于所有对象,属于该类。可以通过类名+作用域限定符直接访问,也可以通过对象. 该方式进行访问。而普通成员无法用类名进行访问,因为普通成员属于对象,无法用类名进行调用访问。因为普通成员属于对象,而采用类名进行调用时无法确定属于哪个对象,导致调用出错。而静态成员全局唯一,为所有类对象共享,不会产生歧义,那么就可以采用类名进行调用。
2)静态成员变量必须在类外定义,定义时不添加static关键字。
3)静态成员函数没有隐藏的this指针,不能访问任何非静态成员。静态成员函数可以用类名进行调用,类名不为对象,无法传一个对象的地址。
4)静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值,const修饰符等参数。
在需要所有对象所公有的一个变量就需要定义一个静态成员。静态成员的大小不算在对象中,因为其不存在对象当中。
3. 静态成员函数
静态成员无法调用非静态成员。
class Date {
public:
void fun() {
getC();
}
static int getC() {
// 静态成员函数不能调用非静态成员函数,因为静态成员函数没有this指针
//fun(this);
return Count;
}
private:
int _year;
static int Count;
};
int Date::Count = 0;
int main() {
fun();
system("pause");
return 0;
}
非静态成员函数可以调用静态成员函数。静态成员函数调用时无特殊需求,可以进行调用。而非静态成员函数调用需要传入this指针,所以不能满足其要求而无法调用。