继承是面向对象编程中的重要概念,子类可以继承父类的成员变量和成员函数,
但当子类和父类出现同名的成员时,就需要考虑如何访问。
继承同名成员处理方式
同名成员变量处理
- 访问子类同名成员变量 直接访问即可
- 访问父类同名成员变量 需要加作用域
即:子类对象可以直接访问到子类中同名成员变量,但访问父类中的同名变量则需要通过子类对象加作用域来实现
代码演示:
#include <iostream>
using namespace std;
class Base {
public:
Base() {
m_A = 100;
}
int m_A;
};
class Son :public Base {
public:
Son() {
m_A = 200;
}
int m_A;
};
//同名成员变量处理
void test01() {
Son s;
cout << "Sin 下的 m_A = " << s.m_A << endl;
//如果通过子类对象,访问到父类中的成员变量,需要加作用域
cout << "Base 下的 m_A = " << s.Base::m_A << endl;
}
int main() {
test01();
system("pause");
return 0;
}
同名成员函数处理
- 访问子类同名成员函数 直接访问即可
- 访问父类同名成员函数 需要加作用域
代码演示:
#include <iostream>
using namespace std;
class Base {
public:
void func() {
cout << "Base - func()调用" << endl;
}
//函数重载
void func(int a) {
cout << "Base - func(int a)调用" << endl;
}
};
class Son :public Base {
public:
void func() {
cout << "Son - func()调用" << endl;
}
};
//同名成员函数处理
void test02() {
Son s;
s.func(); //直接调用,调用的是子类中的同名成员函数
//如何调用到父类中同名成员函数?
//加作用域
s.Base::func();
//当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
//如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域
//s.func(100);//报错
s.Base::func(100);
}
int main() {
test02();
system("pause");
return 0;
}
在上面的演示代码中,有一个新的知识点:
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
隐藏
- 在面向对象编程中,隐藏(hiding)是指子类定义了与父类同名的成员变量或者成员函数,使得子类中的同名成员隐藏掉父类中的同名成员。
- 这种机制可以用于代码重构、防止冲突等方面。
也就是说:
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中所有版本的同名成员函数
什么意思?
在上面的代码演示中:看这两行代码:
s.func(100);//报错
s.Base::func(100);
在test02()中,使用第一行代码,会报错。
如果想访问父类中被隐藏的同名成员函数,需要加父类的作用域。
小结1
总结:
- 子类对象可以直接访问到子类中同名成员
- 子类对象加作用域可以访问到父类同名成员
- 当子类与父类拥有同名的成员函数,子类会隐藏父类中同名成员函数,加作用域可以访问到父类中同名函数
继承同名静态成员处理方式
静态成员和非静态成员出现同名,处理方式一致
- 访问子类同名成员 直接访问即可
- 访问父类同名成员 需要加作用域
静态成员
在讲解下面的内容时,如果不懂得静态成员的使用方式,将看不懂代码。如果你已经懂得如何使用静态成员,可跳过此内容。
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员
静态成员分为:
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
静态成员分为两种访问方式:
- 通过对象
- 通过类名
对于同名静态成员,需要注意到静态成员是属于类的,而不是某个具体的对象。
因此,当通过对象来访问静态成员时,仍然满足上述同名成员的访问规则,优先调用子类中的同名静态成员。而当通过类名来访问静态成员时,则依据采用的作用域来访问该同名成员函数。
同名静态成员变量处理
与同名成员变量处理方式相同
代码演示:
#include <iostream>
using namespace std;
//继承中的同名静态成员处理方式
class Base {
public:
static int m_A;
};
int Base::m_A = 100;
class Son :public Base {
public:
static int m_A;
};
int Son::m_A = 200;
//同名的静态属性
void test01() {
//1、通过对象访问
cout << "通过对象访问:" << endl;
Son s;
cout << " Son 下 m_A = " << s.m_A << endl;//200
cout << " Base 下 m_A = " << s.Base::m_A << endl;//100
//2、通过类名访问
cout << "通过类名访问:" << endl;
cout << " Son 下 m_A = " << Son::m_A << endl;//200
cout << " Base 下 m_A = " << Base::m_A << endl;//200
//通过子类访问到父类的m_A,并且通过类名方式访问
cout << " Base 下 m_A = " << Son::Base::m_A << endl;//200
}
int main() {
test01();
system("pause");
return 0;
}
解释这条代码含义:
cout << " Base 下 m_A = " << Son::Base::m_A << endl;//200
第一个::代表通过类名方式访问
第二个::代表访问父类作用域下
即:通过类名Son的方式访问父类作用域下的m_A
同名静态成员函数处理
与同名成员函数处理方式相同
代码演示:
#include <iostream>
using namespace std;
//继承中的同名静态成员处理方式
class Base {
public:
static void func() {
cout << "Base - static void func()调用" << endl;
}
//重载
static void func(int a) {
cout << "Base - static void func(int a)调用" << endl;
}
};
class Son :public Base {
public:
static void func() {
cout << "Son - static void func()调用" << endl;
}
};
//同名的静态成员函数
void test02() {
//1、通过对象访问
cout << "通过对象访问:" << endl;
Son s;
s.func();//Son - static void func()调用
s.Base::func();
//2、类名方式访问
cout << "通过类名访问:" << endl;
Son::func();
Base::func();
Son::Base::func();
//加上父类作用域
Son::Base::func(100);
}
int main() {
test02();
system("pause");
return 0;
}
解释这条代码含义:
Son::Base::func(100);
为什么不能使用:
Son::func(100);//报错
跟第一部分的成员函数同理:
子类出现和父类同名静态成员函数,也会隐藏父类中所有同名成员函数
如果想访问父类中被隐藏同名成员函数,需要加父类的作用域进行访问
小结2
同名静态成员处理方式和非静态处理方式一样,只不过有两种访问的方式(通过对象 和 通过类名)
总结
综上所述,我们需要谨慎处理子类与父类之间的同名成员问题,以减少命名冲突和易混淆的情况,同时为代码编写过程中注入更多理性思考和准确性原则。希望本篇技术博客的内容能对各位读者有所启发和帮助。