C++构造函数/析构函数 设置成private的原因:
将构造函数,析构函数声明为私有和保护的,那么对象如何创建?
已经不能从外部调用构造函数了,但是对象必须被构造,应该如何解决,麻烦大家帮忙说明,关于构造,析构函数声明为私有和保护时的用法???
提出这个问题,说明你已经对c++有所思考了。
从语法上来讲,一个函数被声明为protected或者private,那么这个函数就不能从“外部”直接被调用了。
对于protected的函数,子类的“内部”的其他函数可以调用之。
而对于private的函数,只能被本类“内部”的其他函数说调用。
语法上就是这么规定的,你肯定也知道的咯。
那么为什么有时候将构造函数或者析构函数声明为protected的或者private的?
通常使用的场景如下:
1。如果你不想让外面的用户直接构造一个类(假设这个类的名字为A)的对象,而希望用户只能构造这个类A的子类,那你就可以将类A的构造函数/析构函数声明为protected,而将类A的子类的构造函数/析构函数声明为public。例如:
- #include <iostream>
- using namespace std;
- class A
- {
- protected:
- A(){}
- public:
- void test(){
- cout << "call A test()" << endl;
- }
- };
- class B : public A
- {
- public: B(){}
- };
- int main(int argc, char** argv)
- {
- A a; // error
- B b; // ok
- b.test();
- }
2. 如果将构造函数/析构函数声明为private,那只能这个类的“内部”的函数才能构造这个类的对象了。这里所说的“内部”不知道你是否能明白,下面举个例子吧。
class A
{
private:
public:
};
上面的代码是能通过编译的。上面代码里的Instance函数就是类A的内部的一个函数。Instance函数体里就构建了一个A的对象。
但是,这个Instance函数还是不能够被外面调用的。为什么呢?
如果要调用Instance函数,必须有一个对象被构造出来。但是构造函数被声明为private的了。外部不能直接构造一个对象出来。
A aObj; // 编译通不过
aObj.Instance();
但是,如果Instance是一个static静态函数的话,就可以不需要通过一个对象,而可以直接被调用。如下:
- #include <iostream>
- using namespace std;
- class A
- {
- private:
- A():data(10){ cout << "A" << endl; }
- ~A(){ cout << "~A" << endl; }
- public:
- static A& Instance()
- {
- static A a;
- return a;
- }
- void Print()
- {
- cout << data << endl;
- }
- private:
- int data;
- };
- int main(int argc, char** argv)
- {
- A& ra = A::Instance();
- ra.Print();
- }
上面的代码其实是设计模式singleton模式的一个简单的C++代码实现。
还有一个情况是:通常将拷贝构造函数和operator=(赋值操作符重载)声明成private,但是没有实现体。
这个的目的是禁止一个类的外部用户对这个类的对象进行复制动作。
引用作为函数返回值的四种形式分析:
函数返回值时,要生成一个值的副本。而用引用返回值时,不生成值的副本。
例如,下面的程序是有关引用返回的4种形式:
//*********************
//** ch9_6.cpp **
//*********************
#include <iostream.h>
float temp;
float fn1(float r)
{
temp = r*r*3.14;
return temp;
}
float& fn2(float r)
{
temp = r*r*3.14;
return temp;
}
void main()
{
float a=fn1(5.0); //1
float& b=fn1(5.0); //2:warning
float c=fn2(5.0); //3
float& d=fn2(5.0); //4
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
cout<<d<<endl;
}
运行结果为:
78.5
78.5
78.5
78.5
对主函数的4种引用返回的形式, 程序的运行结果是一样的。但是它们在内存中的活动情况是各不相同的。其中变量temp是全局数据,驻留在全局数据区data。函数main()、函数fnl()或函数fn2()驻留在栈区stack。
第一种情况:见图9-5。
图9-5 返回值方式的内存布局
这种情况是一般的函数返回值方式。 返回全局变量temp值时,C++创建临时变量并将temp的值78.5复制给该临时变量。返回到主函数后,赋值语句a=fnl(5.0)把临时变量的值78.5复制给a。
第二种情况:见图9-6。
图9-6 返回值初始引用的情形
这种情况下,函数fnl()是以值方式返回的,返回时, 复制temp的值给临时变量。返回到主函数后,引用b以该临时变量来初始化,使得b成为该临时变量的别名。由于临时变量的作用域短暂,所以b面临无效的危险。 根据C++标准,临时变量或对象的生命期在一个 完整的语句表达式结束后便宣告结束,也即在“float& b=fnl(5.0);”之后,临时变量不再存在。 所以引用b以后的值是个无法确定的值。BC对C++标准进行了扩展,规定如果临时变量或对象作为引用的初始化时,则其生命期与该引用一致。14.7节将进一步介绍这一内容。 这样的程序, 依赖于编译器的具体实现,所以移植性是差的。
若要以返回值初始化一个引用,应该先创建一个变量,将函数返回值赋给这个变量,然 后再以该变量来初始化引用,就像下面这样:
int x=fnl(5.0);
int& b=x;
第三种情况:见图9-7。
图9—7 返回引用方式
这种情况,函数fn2()的返回值不产生副本,所以, 直接将变量temp返回给主函数。主函数的赋值语句中的左值,直接从变量temp中得到复制,这样避免了临时变量的产生。当变量temp是一个用户自定义的类型时,这种方式直接带来了程序执行效率和空间利用的利益。
第四种情况:见图9-8。
图9—8 返回引用方式的值作为引用的初始化
这种情况, 函数fn2()返回一个引用,因此不产生任何返回值的副本。在主函数中,一个引用声明d用该返回值来初始化,使得d成为temp的别名。由于temp是全局变量, 所以在d的有效期内temp始终保持有效。这样做法是安全的。
但是, 如果返回不在作用域范围内的变量或对象的引用, 那就有问题了。这与返回一个局部作用域指针的性质一样严重。BC作为编译错误,VC作为警告,来提请编程者注意。例如,下面的代码返回一个引用,来给主函数的引用声明初始化:
float& fn2(float r)
{
float temp;
temp=r*r*3.14;
return temp;
}
void main()
{
float &d=fn2(5.0); //error返回的引用是个局部变量
}
见图9-9说明。
图9-9 返回的引用是局部变量
如果返回的引用是作为一个左值进行运算,也是程序员最犯忌的。所以,如果程序中有下面的代码,则一定要剔除:
float& fn2(float r)
{
float temp;
temp=r*r*3.14;
return temp;
}
void main()
{
fn2(5.0)=12.4; //error返回的是局部作用域内的变量
}
转载地址:http://blog.csdn.net/tcdddd/article/details/5519332