C++之继承<2>【详解】
1. 派生类的默认成员函数
1.1 1. 构造成员函数
无论是否显示的调用基类的构造成员函数,都会自动调用基类的默认成员函数:
#include <iostream>
using namespace std;
class Person
{
public:
Person(const char* name = "peter")
: _name(name)
{
cout << "Person()" << endl;
}
string _name;
};
class Student : public Person
{
public:
Student(const char* name, int num)
: _num(num)
{
cout << "Student()" << endl;
}
protected:
int _num;
};
int main()
{
Student s1("jack", 18);
return 0;
}
显示调用后:
上述的后半段的意义是:如果基类没有默认的构造函数,那么是这样的:
Person(const char* name = "peter")
: _name(name)
{}
可以进行传参来构造对象,如果你在派生类没有显示的调用它,那么不能进行进行传参来构造。
#include <iostream>
using namespace std;
class Person
{
public:
Person(const char* name = "peter")
: _name(name)
{
cout << "Person()" << endl;
}
string _name;
};
class Student : public Person
{
public:
Student(const char* name, int num)
: _num(num)
{
cout << "Student()" << endl;
}
protected:
int _num;
};
int main()
{
Student s1("jack", 18);
cout << s1._name;
return 0;
}
上图可以看到,传入的参数是“jack”, 但是构造出来的对象属性是“peter”。
至于必须在初始化列表显示的调用,是因为祖师爷定下的规则是,先构造基类再构造派生类,初始化列表是先于构造函数执行的。
Person(name)在初始化列表中的顺序可以随意改动的,因为初始化列表的执行顺序只跟声明的顺序有关,跟初始化列表中的先后顺序无关。
1.2 拷贝复制
分别是拷贝构造函数和operator=复制函数:
上面两条的原因和构造函数的一样,就不在赘述。
下面是验证的代码:
#include <iostream>
using namespace std;
class Person
{
public:
Person(const char* name = "peter")
: _name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
: _name(p._name)
{
cout << "Person(const Person& p)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person operator=(const Person& p)" << endl;
if (this != &p)//防止复制相同的对象,相同的就不必进行下面步骤了
_name = p._name;
return *this;
}
protected:
string _name; // 姓名
};
class Student : public Person
{
public:
Student(const char* name, int num)
: Person(name)
, _num(num)
{
cout << "Student()" << endl;
}
Student(const Student& s)
: Person(s)
, _num(s._num)
{
cout << "Student(const Student& s)" << endl;
}
Student& operator = (const Student& s)
{
cout << "Student& operator= (const Student& s)" << endl;
if (this != &s)//防止复制相同的对象,相同的就不必进行下面步骤了
{
Person::operator =(s);
_num = s._num;
}
return *this;
}
protected:
int _num; //学号
};
int main()
{
Student s1("jack", 18);
Student s2(s1);
return 0;
}
1.3 构造函数和析构函数的执行顺序
-
首先,为什么一定先调用基类构造函数再调用派生类的的构造函数呢?
如果你先调用派生类的构造函数,派生类是继承基类的,那么派生类中就可以使用基类中的属性和行为,但是此时还没有调用基类的构造函数,所以不能这样。 -
为什么一定先调用派生类的析构函数再调用基类的析构函数呢?
如果先调用基类的析构函数的话,会释放掉一些变量或指针,那么派生类使用继承过来的这些变量或者指针的时候,它们已经变成了野指针,因此不能如此。
下面是完整代码,大家可以尝试验证:
#include <iostream>
using namespace std;
class Person
{
public:
Person(const char* name = "peter")
: _name(name)
{
cout << "Person()" << endl;
}
Person(const Person& p)
: _name(p._name)
{
cout << "Person(const Person& p)" << endl;
}
Person& operator=(const Person& p)
{
cout << "Person operator=(const Person& p)" << endl;
if (this != &p)
_name = p._name;
return *this;
}
~Person()
{
cout << "~Person()" << endl;
}
protected:
string _name; // 姓名
};
class Student : public Person
{
public:
Student(const char* name, int num)
: Person(name)
, _num(num)
{
cout << "Student()" << endl;
}
Student(const Student& s)
: Person(s)
, _num(s._num)
{
cout << "Student(const Student& s)" << endl;
}
Student& operator = (const Student& s)
{
cout << "Student& operator= (const Student& s)" << endl;
if (this != &s)
{
Person::operator =(s);
_num = s._num;
}
return *this;
}
~Student()
{
cout << "~Student()" << endl;
}
protected:
int _num; //学号
};
int main()
{
Student s1("jack", 18);
Student s2(s1);
Student s3("rose", 17);
s1 = s3;
return 0;
}
2. 继承和友元
#include <iostream>
using namespace std;
class Student;
class Person
{
public:
friend void Display(const Person& p, const Student& s);
protected:
string _name = "zhangsan"; // 姓名
};
class Student : public Person
{
public:
protected:
int _num; //学号
};
void Display(const Person& p, const Student& s)
{
cout << p._name << endl;
cout << s._num << endl;
}
int main()
{
Student s;
Person p;
Display(p, s);
return 0;
}
从上面图中可以看出。
3. 继承与静态成员
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person()
{
++_count;
++age;
}
public:
static int _count;
int age = 0; // 姓名
};
int Person::_count = 0;
class Student : public Person
{
public:
protected:
int _num; //学号
};
int main()
{
Student s;
Person p;
cout << "Person::_count: "<<Person::_count<<endl;
cout << "Person::age: "<<p.age<<endl;
return 0;
}
运行结果是:
由此可见,静态成员_count是共有的,只有一个。