详细介绍:C++工程实战入门笔记12-继承、派生、保护、公开、私有
代码
#include<iostream>
using namespace std;
#include<string>
//基类:父类
class Base
{
public:
Base() { cout <<
"create base " << name<<endl;
}
Base(int i) { cout << i <<
"Create Base" << endl;
}
~Base() { cout <<
"drop base " << name << endl;
}
void BaseFun() { cout <<
"call BaseFun\n";
}
//一个int占4个字节,以下三个int,共占12字节
int index{
0
};
int x{
0
};
int y{
0
};
string name{
"BaseName"
};
void Test() { cout <<
"BaeTest" << endl;
}
protected://自己和派生类
int pid{
0
};
void PFunc() {
cout <<
"Base::PFunc called" << endl;
};
private:
int pri{
0
};
};
//派生类A继承了Base成员变量和函数
class A
:public Base
{
public://默认调用无参构造
A() :Base(100)//设置选用不同的基类构造函数
{ cout <<
"create A" <<name<< endl;
}
~A() { cout <<
"drop A" <<name<< endl;
}
void AFunc() { cout <<
"Afunc" << endl;
}
void Test() { cout <<
"Atest" << endl;
}
int a_index{
0
};
string name{
"AName"
};
//派生类重新定义name
};
//保护继承Base的public变派生类的protected
class ProClass
:protected Base
{
public:
ProClass() {
this->index++;
this->pid++;
PFunc();
}
int pro_index{
0
};
};
class ProClassChild
:public ProClass
{
public://可以访问Base的pub和pro
ProClassChild() {
this->
PFunc();
}
};
//私有继承
class PriClass
:private Base
{
public:
PriClass() {
this->
PFunc();
}
};
class PriClassChild
:public PriClass
{
//不能访问Base中任何成员和方法
};
int main()
{
Base b;
cout <<
sizeof(b) <<
":" <<
&b << endl;
//12字节,没问题
{
cout <<
"======================A begin====================" << endl;
A a1;
a1.Test();
a1.Base::Test();
}
cout <<
"======================A end====================" << endl;
/*cout << "======================A===================="<<endl;
A a1;
a1.index++;
//派生类访问基类的成员变量和函数
cout << a1.index << endl;
cout << "调用函数:" << endl;
a1.BaseFun();
a1.AFunc();*/
{
ProClass pc;
pc.pro_index;
}
system("pause");
}
继承的基本概念
继承允许我们根据一个已有的类(基类或父类,如 Base)来定义一个新的类(派生类或子类,如 A, ProClass)。它的主要目的是实现代码的重用和功能扩展。派生类自动获得基类的所有成员(变量和函数),并可以添加自己新的成员,或者修改基类成员的行为(通过重写,但本例未展示)。
- 代码体现: 类 A 通过 : public Base 语法公开继承了 Base 的所有 public 和 protected 成员。
类成员的访问控制
- public (公有): 可以被任何函数访问。
- protected (保护): 只能被这个类自身和它的派生类访问。外部代码无法访问。例如 Base 中的 pid 和 PFunc(),A 和 ProClass 的内部可以访问它们,但 main 函数中不行。
- private (私有): 只能被这个类自身访问。即使是它的派生类也无法访问。例如 Base 中的 pri,只有 Base的成员函数能访问它,A 完全不知道它的存在。
继承方式
代码体现:
- class A : public Base -> A 的对象在 main 中可以调用 BaseFun() 和访问 index。
- class ProClass : protected Base -> ProClass 的对象在 main 中不能调用 BaseFun() 或访问 index(因为它们变成了 protected),但其派生类 ProClassChild 可以。
- class PriClass : private Base -> PriClass 的对象在 main 中不能访问 Base的任何成员,其派生类 PriClassChild 也不能。
派生类的内存模型
一个派生类对象的内存包含两部分:
- 基类子对象 (Base subobject): 继承自基类的所有数据成员。
- 派生类部分: 派生类自己定义的新数据成员。
代码体现: - sizeof(b) 打印 40(在64位系统上,string 通常占32字节,3个 int 占12字节,内存对齐到8的倍数可能是40字节)。
- A a1; 的大小会比 Base 更大,因为它包含了 Base 的所有成员 (index, x, y, name) 再加上自己的成员 (a_index, name)。注意,派生类中与基类同名的成员变量是两个不同的变量,存放在内存的不同位置。
构造与析构的顺序
对象的创建和销毁遵循严格的顺序,这是由编译器自动管理的。
- 构造顺序 (Construction Order):
基类部分: 调用基类的构造函数。
派生类部分: 调用派生类的构造函数。
输出: create base -> create A
- 析构顺序 (Destruction Order): 与构造顺序完全相反。
派生类部分: 调用派生类的析构函数。
基类部分: 调用基类的析构函数。
输出: drop A -> drop base
名字遮蔽 (Name Hiding)
如果派生类中定义了与基类同名的成员(变量或函数),那么基类中的那个成员会被“遮蔽”起来。
在派生类中,直接使用名字默认访问的是派生类自己的成员。如果需要访问被遮蔽的基类成员,需要使用作用域解析运算符 ::,例如 a1.Base::name。
代码体现: Base 和 A 都有一个 string name;。在 A 的对象 a1 中,a1.name 访问的是 A::name (“AName”),而要访问基类的名字则需要 a1.Base::name (“BaseName”)。
基类不同构造函数的处理
当基类有多个构造函数时,派生类需要明确指定调用哪一个基类构造函数。这通过在派生类构造函数的初始化列表中调用基类构造函数来实现。
#include <iostream>
#include <string>
using namespace std;
class Base
{
public:
// 默认构造函数
Base() : x(0), y(0), name("Default") {
cout <<
"Base default constructor" << endl;
}
// 带参数的构造函数
Base(int x, int y, string name) : x(x), y(y), name(name) {
cout <<
"Base parameterized constructor" << endl;
}
// 拷贝构造函数
Base(const Base& other) : x(other.x), y(other.y), name(other.name) {
cout <<
"Base copy constructor" << endl;
}
void display() {
cout <<
"Base: x=" << x <<
", y=" << y <<
", name=" << name << endl;
}
protected:
int x, y;
string name;
};
class Derived
: public Base {
public:
// 派生类默认构造函数,隐式调用基类默认构造函数
Derived() : z(0) {
cout <<
"Derived default constructor" << endl;
}
// 派生类构造函数,显式调用基类带参数的构造函数
Derived(int x, int y, string name, int z) : Base(x, y, name), z(z) {
cout <<
"Derived parameterized constructor" << endl;
}
// 派生类拷贝构造函数,显式调用基类拷贝构造函数
Derived(const Derived& other) : Base(other), z(other.z) {
cout <<
"Derived copy constructor" << endl;
}
void display() {
Base::display();
cout <<
"Derived: z=" << z << endl;
}
private:
int z;
};
int main() {
cout <<
"=== 创建派生类默认对象 ===" << endl;
Derived d1;
d1.display();
cout <<
"\n=== 创建派生类参数化对象 ===" << endl;
Derived d2(10, 20, "Test", 30);
d2.display();
cout <<
"\n=== 创建派生类拷贝对象 ===" << endl;
Derived d3 = d2;
d3.display();
return 0;
}

浙公网安备 33010602011771号