不需显式地调用,在创建类对象时,编译器自动调用的函数.构造函数和析构函数就是这种函数.
构造函数特点: 1、函数名与类名相同;
2、无返回值。
class C{
public:
C() { name = “Unknown”;}
C( string& n ) { name = n; }
private:
string name;
}
int main() {
C c1; // name = “Unknown”
C c2( “Jack” ); // name = “Jack”
return 0;
}
看到没?这便是构造函数的神奇之处!!
下面分别剖析知识点:
一、构造函数可以约束对象创建。
比如说有这种情况:如果你想创建一个对象,那你必须同时给出它的编号,否则连门都没有!!见下例:
class Book {
public:
Book( unsigned ID ) { id = ID; }
private:
Book();
unsigned id;
};
void main() {
Book a; // ERROR !!不给出编号别想成功创建!
Book b(152465771); // OK! 可以.
}
其实,即使把“ Book(); ” 删掉, a 照样定义不成。因为 Book 类没有提供公有的默认构造函数。
多数情况下,编译器会为类生成一个公有的默认构造函数,只有以下两种情况除外:
一、一个类显式声明了任何构造函数(不管是不是默认函,只要是构造函数),编译器不生成默认构造函数!这时候,想要默认函,就少玩会儿《World of Warcraft》,自己动手鼓捣一个!!
二、一个类声明了一个非公有的默认构造函数,编译器不生成默认构造函数。
回归本例,因为Book 类显式声明一个构造函数了,所以编译器便不再自作主张生成个默认的了。于是呢, a 就郁闷了,咋会儿事呢?我到底哪里做错了呢?Book 类,还有main 函数,你们有没有考虑我的感受……
二、拷贝构造函数
class Person {
public:
height
weight
age
address
hobby
...
Person( Person& );
};
void main() {
Person Jack;
Person Tom( Jack ); //这便是是拷贝构造函数,经这么一搞,
} //Tom的一切个人资料
构造函数有两种原型:
Person( Person& );
Person( const Person& );
两种原型都是引用,因此 Person( Person ); 是错误的!
可以有多于一个参数,但第一个以后的所有参数都必须有默认值:
Person( const Person& p, bool married = false );
什么时候应该为类设计拷贝构造函数呢?
答:当一个类包含指向动态存储空间指针的数据成员,这时候就很有必要为该类设计一个拷贝构造函数了。因为编译器生成的拷贝构造函数会使 Tom 和 Jack 指向相同的某个存储空间,这样任何一方资料的改动都会导致另一方的也莫名其妙地改了,“死都不知道怎么死的”,这是非常危险的!!
正确的做法是自己动手设计一个拷贝构造函数,使Tom 指向另一块儿存储空间,其空间里的内容和 Jack 的一模一样。见下例:
使用编译器生成的拷贝函数版本:
#include<iostream>
#include<string>
using namespace std;
class Namelist {
public:
Namelist() { size = 0; p = 0; }
Namelist( const string [], int );
void set( const string& , int );
void set( const char* , int );
void dump() const;
private:
int size;
string* p;
};
Namelist::Namelist( const string s[], int si ) {
p = new string[ size = si ];
for ( int i = 0; i < size; i++ )
p[ i ] = s[ i ];
}
void Namelist::set(const string& s, int i ) {
p[ i ] = s;
}
void Namelist::set( const char* s, int i ) {
p[ i ] = s;
}
void Namelist::dump() const {
for ( int i = 0; i < size; i++ )
cout << p[ i ] << '/t';
cout << endl;
}
int main() {
string list[] = { "Lab", "Husky", "Collie" };
Namelist d1( list, 3 );
d1.dump();
Namelist d2( d1 );
d2.dump();
d2.set( "Great Dane", 1 );
d2.dump();
d1.dump();
return 0;
}
输出为:
Lab Husky Collie
Lab Husky Collie
Lab Great Dane Collie
Lab Great Dane Collie
用两张图片来解释原因吧:
这便是为什么 d1的数据被莫名其妙地改了! 这便是《谁动了我的奶酪》!!
那么且看正确的方法——
自定义拷贝构造函数版本:
#include<iostream>
#include<string>
using namespace std;
class Namelist {
public:
Namelist() { size = 0; p = 0; }
Namelist( const string [], int );
Namelist( const Namelist& );
void set( const string& , int );
void set( const char* , int );
void dump() const;
private:
int size;
string* p;
void copyIntop( const Namelist& );
};
Namelist::Namelist( const string s[], int si ) {
p = new string[ size = si ];
for ( int i = 0; i < size; i++ )
p[ i ] = s[ i ];
}
Namelist::Namelist( const Namelist& d ) {
p = 0;
copyIntop( d );
}
void Namelist::set( const string& s, int i ) {
p[ i ] = s;
}
void Namelist::set( const char* s, int i ) {
p[ i ] = s;
}
void Namelist::dump() const {
for ( int i = 0; i < size; i++ )
cout << p[ i ] << '/t';
cout << endl;
}
void Namelist::copyIntop( const Namelist& d ) {
delete[] p;
if( d.p != 0 ) {
p = new string[ size = d.size ];
for ( int i = 0; i < size; i++ )
p[ i ] = d.p[ i ];
}
else {
p = 0;
size = 0;
}
}
int main() {
string list[] = { "Jack", "Tom", "Lily" };
Namelist d1( list, 3 );
d1.dump();
Namelist d2( d1 );
d2.dump();
d2.set( "Armstrong", 1 );
d2.dump();
d1.dump();
return 0;
}
输出结果是:
Jack Tom Lily
Jack Tom Lily
Jack Armstrong Lily
Jack Tom Lily
原理:
很明显,对 d2 的修改不会再牵制到 d1 的任何数据了,智慧的古巴比伦法老制定了《十二铜表法》,其中最著名的一条便是“私有财产,神圣不可侵犯”。天知道,这句话对后来的世界发展是多么的至关重要!!社会主义不敢说,反正我就知道几百年来任何模式、形状和程度的资本主义制度都是在这句话上繁衍而来的。可喜的是,在本程序中,也看到了这一点。
三、转型构造函数
用于类型转换,只有一个参数。
#include<iostream>
using namespace std;
class Person {
public:
Person() { name = "Unkown"; }
Person( const char* n ) { name = n; }
private:
string name;
};
int main() {
const char* p = "souphy";
Person S( p );
return 0;
}
看到没?本来私有数据成员 name 是个吊 string 类型的。可参数明明是个 const char 类型的指针,只所以能够创建成功,原因就在于 Person( const char* n ) { name = n; } 在背地里给它使着劲呢!
你懂了吗?!!!