文章主要来源于帖子 https://www.cnblogs.com/mt-luo/p/4162524.html,但对博主的总结提出个人不同的见解,他提到对象指针不能用参数列表,经过查找相关资料以及实践,其实这是允许的。
- 在一个类中内嵌套另一个类的对象作为数据成员,这样可以称为类的组合。类中的成员数据是另一个类的对象。通过类的组合可以在已有的抽象的基础上实现更复杂的抽象。该内嵌对象称为对象成员,或者子对象。如学生类Student的内嵌课程类Course作为数据成员;
class Student{
private:
Course *m_course;
public:
};
在使用过程中,需要着重注意的是 对象成员的初始化!如Student的构造函数该如何定义?
如果一个类具有内嵌对象,那么在它对象化的时候既要对基本数据成员初始化也要对内嵌的对象成员初始化。
class X { 类名1 对象成员名1; 类名2 对象成员名2; ... 类名n 对象成员名n; };
一般来说类X的构造函数定义形式为:
X::X(形参表0):对象成员名1(形参1),...,对象成员名n(形参n) { 类X的构造函数体 }
形参1到n一般来自形参表0;而且当调用构造函数的时候,首先按照在类的声明中的顺序依次调用对象成员函数的构造函数,对这些对象初始化,最后执行够赞函数体初始化类中的其他数据成员;析构函数的调用顺序与构造函数相反!举例说明:
#include<iostream>
using namespace std;
class Node
{
private:
double x_;
double y_;
public:
Node(double x=0,double y=0) //带默认参数的构造函数
{
x_=x;
y_=y;
cout<<"x="<<x_<<endl;
}
~Node() //Node类的析构函数
{
cout<<"x="<<x_<<endl;
}
};
class Triangle
{
private:
Node nodei;
Node nodej;
Node nodem;
public:
Triangle(double a1,double b1,double a2,double b2,double a3,double b3):nodei(a1,b1),
nodej(a2,b2),nodem(a3,b3)//内嵌对象成员的Triangle类的构造函数定义
{}
~Triangle() //Triangle类析构函数
{}
};
int main()
{
Triangle tri(1,1,2,2,3,3); //初始化
return 0;
}
输出结果:
说明:如果类的内嵌对象是用指针表示的,如何初始化呢?这个时候用上述的初始化列表就失效了??并不是
#include<iostream>
using namespace std;
class Node
{
private:
double x_;
double y_;
public:
Node(double x=0,double y=0) //带默认参数的构造函数
{
x_=x;
y_=y;
cout<<"x="<<x_<<endl;
}
void init(double x,double y)//自定义初始化函数
{
x_=x;
y_=y;
}
~Node() //Node类的析构函数
{
cout<<"x="<<x_<<endl;
}
void disp(void) //输出函数
{
cout<<"x="<<x_<<endl;
}
};
class Triangle
{
private:
Node *nodei; //数据成员为指向Node类型的指针
Node *nodej;
Node *nodem;
public:
Triangle(double a1,double b1,double a2,double b2,double a3,double b3)
{
Node *node1,*node2,*node3;
//定义参量指针
node1=new Node; //动态分配内存
node2=new Node;
node3=new Node;
node1->init(a1,b1); //调用自定义init()初始化三个点
node2->init(a2,b2);
node3->init(a3,b3);
nodei=node1; //再将初始化也即分配了内存后的指针值赋给数据成员
nodej=node2;
nodem=node3;
nodei->disp(); //打印赋值结果
nodej->disp();
nodem->disp();
//delete node3; //释放指针所指
//delete node2;
//delete node1;
}
~Triangle() //Triangle类析构函数
{
}
void disp()
{
nodei->disp();
nodej->disp();
nodem->disp();
}
};
int main()
{
Triangle tri(1,1,2,2,3,3); //初始化
tri.disp();
return 0;
}
输出结果为:
显然这样定义构造函数既不直观(不知道那个参数对应那个点)也很麻烦!改为如下:
#include<iostream>
using namespace std;
class Node
{
private:
double x_;
double y_;
public:
Node(double x=0,double y=0) //带默认参数的构造函数
{
x_=x;
y_=y;
cout<<"x="<<x_<<endl;
}
void init(double x,double y)//自定义初始化函数
{
x_=x;
y_=y;
}
~Node() //Node类的析构函数
{
cout<<"x="<<x_<<endl;
}
void disp(void) //输出函数
{
cout<<"x="<<x_<<endl;
}
};
class Triangle
{
private:
Node *nodei; //数据成员为指向Node类型的指针
Node *nodej;
Node *nodem;
public:
Triangle(Node& node1,Node& node2,Node& node3)
{
//nodei=new Node; //动态分配内存
//nodej=new Node;
//nodem=new Node;
nodei=&node1; //地址传递
nodej=&node2;
nodem=&node3;
nodei->disp(); //打印赋值结果
nodej->disp();
nodem->disp();
//delete node3; //释放指针所指
//delete node2;
//delete node1;
}
~Triangle() //Triangle类析构函数
{
}
void disp()
{
nodei->disp();
nodej->disp();
nodem->disp();
}
};
int main()
{
Node nod1(1,1),nod2(2,2),nod3(3,3);
Triangle tri(nod1,nod2,nod3); //初始化
//tri.disp();
return 0;
}
输出:
这样来定义构造函数既没有用到init()自定义的初始化函数,而且物理意义明确。
或者通过参数带对象指针的参数列表定义构造函数,
/******************/
#include <iostream>
#include <string>
using namespace std;
class Course{
private:
string m_name;
double m_credit;
int m_score;
public:
Course():m_name("Math"),m_credit(3.5),m_score(0){
}
Course(string name,double credit,int score):m_name(name),m_credit(credit),m_score(score){
}
void show(){
cout<<m_name<<" "<<m_credit<<" "<<m_score<<endl;
}
};
class Student{
private:
Course *m_course;
public:
Student(Course *cour):m_course(cour){
//m_course=cour;
}
void show(){
m_course->show();
}
};
int main(int argc,char *argv[]){
Course cour; //无参的构造函数
Course cour("science",3.6,90); //有参数的构造函数
Student stu(&cour);
stu.show();
return 0;
}
结果运行正确!!
*************************************************更新******************************************************************
在补充一点:
组合类对象成员的构造函数可以直接调用无参数的构造函数,
/******************/
#include <iostream>
#include <string>
using namespace std;
class Course{
private:
string m_name;
double m_credit;
int m_score;
public:
Course():m_name("Math"),m_credit(3.5),m_score(0){
}
Course(string name,double credit,int score):m_name(name),m_credit(credit),m_score(score){
}
void show(){
cout<<m_name<<" "<<m_credit<<" "<<m_score<<endl;
}
};
class Student{
private:
Course m_course;
public:
Student():m_course(){
//m_course=cour;
}
void show(){
m_course.show();
}
};
int main(int argc,char *argv[]){
Course cour; //无参的构造函数
//Course cour("science",3.6,90); //有参数的构造函数
Student stu;
stu.show();
return 0;
}
总结:
- 有子对象的类的初始化问题。子对象不是直接用类名表示,可以用初始化列表初始化。
- 如果子对象用指针形式表示,用初始化列表或者不用初始化列表。