转载自:http://www.cnblogs.com/CaiNiaoZJ/archive/2011/08/06/2129329.html
我们经常会看到一个类中可能会出现另一个类的对象作为它的数据成员,既然是对象,那么就会涉及到这个对象成员要初始化的问题。而程序中各种数据的共享,在一定程度上破环了数据的安全性。C++中有什么方法可以保证数据共享又防止数据改动。另外除以上两个问题,我还将说说C++的多文件程序。
1.我们在创建类的对象时,如果这个类具有内嵌的对象,那么该对象成员也将被自动创建。所以创建对象时既要对本类的基本数据成员初始化,又要对内嵌的对象初始化。具体怎么做呢,我还是用Employee(雇员)和Salary(薪水)两个类来举个实例:
#include "stdafx.h"
#include<string>
#include<iostream>
class Employee
{
private:
std::string id;
std::string name;
public:
Employee(std::string id,std::string name);
~Employee();
void showEmployee();
};
Employee::Employee(std::string id,std::string name):id(id),name(name)
{
std::cout<<"构造对象employee"<<std::endl;
}
Employee::~Employee()
{
std::cout<<"释放对象employee内存空间"<<std::endl;
}
void Employee::showEmployee()
{
std::cout<<"编号:"<<id<<std::endl;
std::cout<<"姓名:"<<name<<std::endl;
}
class Salary
{
private:
Employee employee; //雇员
double wage;//工资
double bonus;//奖金
double commission;//提成
double allowance;//津贴
double subsidy;//补贴
public:
Salary(double wage,double bonus,double commission,double allowance,double subsidy,std::string id,std::string name);
~Salary();
void showSalary();
};
Salary::Salary(double wage,double bonus,double commission,double allowance,double subsidy,std::string id,std::string name):wage(wage),bonus(bonus),commission(commission),allowance(allowance),subsidy(subsidy),employee(id,name)//初始化对象成员employee
{
std::cout<<"构造对象salary"<<std::endl;
}
Salary::~Salary()
{
std::cout<<"释放对象salary内存空间"<<std::endl;
}
void Salary::showSalary()
{
employee.showEmployee();//显示雇员信息
std::cout<<"薪水:"<<std::endl;
std::cout<<" 工资:"<<wage<<std::endl;
std::cout<<" 奖金:"<<bonus<<std::endl;
std::cout<<" 提成:"<<commission<<std::endl;
std::cout<<" 补贴:"<<subsidy<<std::endl;
std::cout<<" 津贴:"<<allowance<<std::endl;
}
int main()
{
{
Salary salary(3000,3000,0,200,100,"001","aaa");
salary.showSalary();
}
return0;
}
结果:
从初始化成员对象的代码中可以看到其实和之前所说的成员初始化表对数据成员初始化的形式是一样的。看到main函数体里的实现部分,可能有人会问那个大括号是否画蛇添足了。如果单单是从程序运行的流程考虑,的确没什么必要。而我特意加上这个大括号是为了说明在系统编译运行时它的顺序是怎么样的,从显示的结果来看,是先调用了Employee()的构造函数,在调用自己(Salary())的构造函数,而在调用各自的析构函数时则刚好相反。也许有人会问,那如果Salary里的对象成员不只一个,那么这些对象成员的构造函数调用的顺序是怎么样的?其实系统编译运行时对对象成员的构造函数调用的顺序是根据其在类声明中的顺序来依次调用,而释放对象空间(析构函数)的过程则刚好相反;
2.C++的常类型的引入,就是为了既保证数据共享又防止数据被改动。在面向对象里常类型主要有常对象、常数据成员以及常成员函数。(1)常对象的形式有:类名 const 对象名[参数表]或const 类名 对象名[参数表],常对象中的数据成员值在对象的整个对象的生存期内不能被改变,而且常对象不能调用普通成员函数,只能调用常成员函数。(2)常数据成员的形式其实和C++对C语言的非面向对象特性扩充(1)所讲到过的常量是一样,但要注意的是类里的常数据成员只能通过初始化列表对其进行初始化,其他函数都不能对其赋值;(3)常成员函数的形式:类型 函数名(参数表) const,const是函数类型的组成部分,所以在声明函数和定义函数时都要加关键字const;同样我们以Employee(雇员)类为例:
#include "stdafx.h"
#include<string>
#include<iostream>
class Employee
{
private:
const std::string id;//常数据成员
const std::string name;//常数据成员
public:
Employee(std::string id,std::string name);
~Employee();
void showEmployee();//普通成员函数
void showEmployee() const;//常成员函数
};
Employee::Employee(std::string id,std::string name):id(id),name(name)
{
//std::cout<<"构造对象employee"<<std::endl;
}
Employee::~Employee()
{
//std::cout<<"释放对象employee内存空间"<<std::endl;
}
void Employee::showEmployee()
{
std::cout<<"普通成员函数:"<<std::endl;
std::cout<<"编号:"<<id<<std::endl;
std::cout<<"姓名:"<<name<<std::endl;
}
void Employee::showEmployee() const
{
std::cout<<"常成员函数:"<<std::endl;
std::cout<<"编号:"<<id<<std::endl;
std::cout<<"姓名:"<<name<<std::endl;
}
int main()
{
Employee employee("001","aa");
employee.showEmployee();
std::cout<<"********************************"<<std::endl;
Employee const const_employee("002","bb");//常对象
const_employee.showEmployee();
return0;
}
结果:
从上述示例代码中,我可以看到两个同名函数void showEmployee(),一个是普通成员函数,一个是常成员函数,它们是重载的,由此说明const可以被用于对重载函数的区分;
3.C++的源程序基本上由3个部分组成:类的声明部分、类的实现部分和类的使用部分,针对3个部分,C++中对应分为3个文件:类声明文件(*.h文件)、类的实现文件(*.cpp)和类的使用文件(*.cpp,主函数main文件)。那么为什么C++中的要使用多文件,一个*.cpp类的使用文件就可解决的问题,为何那么麻烦要分三步走呢?主要有以下几个方面:(1)类的实现文件通常会比较大,将类的声明和实现放在一起,不利于程序的阅读、管理和维护。我们通常说接口应该和实现的部分分离,这样可以更易于修改程序。(2)把类成员函数的实现放在声明文件中和单独放实现文件里,在编译时是不一样的。前者是作为类的内联函数来处理的。(3)对于软件的厂商来说,它只需向用户提供程序公开的接口,而不用公开程序源代码。从这一点来看,我觉得C++在面向对象方面比C#更加明确,清晰。
4.最后还是一样,我将用一个示例来总结一下今天所讲的内容,同时将把程序按照C++多文件的原则分成3个文件来实现(开发工具:vs2010):
1.声明文件*.h:
employee.h(雇员类的声明文件)
View Code
#include<string>
#include<iostream>
class Employee
{
private:
const std::string id;//常数据成员
const std::string name;//常数据成员
public:
Employee(std::string id,std::string name);
~Employee();
void showEmployee();//普通成员函数
void showEmployee() const;//常成员函数
};
salary.h(薪水类的声明文件)
View Code
#include "employee.h"
class Salary
{
private:
const Employee employee; //雇员
constdouble wage;//工资(常数据成员)
double bonus;//奖金
double commission;//提成
double allowance;//津贴
double subsidy;//补贴
public:
Salary(double wage,double bonus,double commission,double allowance,double subsidy,std::string id,std::string name);
~Salary();
void showSalary();
};
2.实现文件*.cpp:
employee.cpp(雇员类的实现文件)
View Code
#include "stdafx.h"
#include<iostream>
#include "employee.h"
Employee::Employee(std::string id,std::string name):id(id),name(name)
{
std::cout<<"构造对象employee"<<std::endl;
}
Employee::~Employee()
{
std::cout<<"释放对象employee内存空间"<<std::endl;
}
void Employee::showEmployee()
{
std::cout<<"普通成员函数:"<<std::endl;
std::cout<<"编号:"<<id<<std::endl;
std::cout<<"姓名:"<<name<<std::endl;
}
void Employee::showEmployee() const
{
std::cout<<"常成员函数:"<<std::endl;
std::cout<<"编号:"<<id<<std::endl;
std::cout<<"姓名:"<<name<<std::endl;
}
salary.cpp(薪水类的实现文件)
View Code
#include "stdafx.h"
#include<iostream>
#include "salary.h"
Salary::Salary(double wage,double bonus,double commission,double allowance,double subsidy,std::string id,std::string name):wage(wage),bonus(bonus),commission(commission),allowance(allowance),subsidy(subsidy),employee(id,name)
{
std::cout<<"构造对象salary"<<std::endl;
}
Salary::~Salary()
{
std::cout<<"释放对象salary内存空间"<<std::endl;
}
void Salary::showSalary()
{
employee.showEmployee();//显示雇员信息
std::cout<<"薪水:"<<std::endl;
std::cout<<" 工资:"<<wage<<std::endl;
std::cout<<" 奖金:"<<bonus<<std::endl;
std::cout<<" 提成:"<<commission<<std::endl;
std::cout<<" 补贴:"<<subsidy<<std::endl;
std::cout<<" 津贴:"<<allowance<<std::endl;
}
3.使用文件*.cpp
main主函数文件
#include "stdafx.h"
#include<iostream>
#include "salary.h"
int main()
{
{
Salary salary(3000,3000,0,200,100,"001","aaa");
salary.showSalary();
}
return0;
}
结果: