名字遮蔽与类作用域/继承的特殊关系
名字遮蔽:基类的成员函数和派生类的成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数。
名字遮蔽:如果派生类中的成员(包括成员变量和成员函数)和基类中的成员重名,通过派生类对象或者在派生类的成员函数中使用该成员时,将使用派生类新增的成员,而不是基类的。
当存在继承关系时,基类的作用域嵌套在派生类的作用域中。如果成员在派生类的作用域中已经找到,就不会在基类作用域中继续查找;如果没有找到,则继续在基类作用域中查找。
基类的成员函数和派生类的成员函数不会构成重载,如果派生类有同名函数,那么就会遮蔽基类中的所有同名函数。
基类
派生类
派生类将基类覆盖掉了,就是派生类和基类不能重载。
将派生类的注释掉,基类函数实现重载
类作用域
- 在成员名前面加类名和域解析符可以访问对象的成员。
- 如果不存在继承关系,类名和域解析符可以省略不写。
- 当存在继承关系时,基类的作用域嵌套在派生类的作用域中。如果成员在派生类的作用域中已经找到,就不会在基类作用域中继续查找;如果没有找到,则继续在基类作用域中查找。
- 如果在成员的前面加上类名和域解析符,就可以直接使用该作用域的成员。
在类的作用域之外,普通的成员只能通过对象(可以是对象本身,也可以是对象指针或对象引用)来访问,静态成员可以通过对象访问,也可以通过类访问。
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class A { // 基类
public:
int m_a=10;
void func() { cout << "调用了A的func()函数。\n"; }
};
class B :public A { // 子类
public:
int m_a = 20;
void func() { cout << "调用了B的func()函数。\n"; }
};
class C :public B { // 孙类
public:
int m_a = 30;
void func() { cout << "调用了C的func()函数。\n"; }
void show() {
cout << "C::m_a的值是:" << C::m_a << endl;
cout << "B::m_a的值是:" << B::m_a << endl;
cout << "A::m_a的值是:" << B::A::m_a << endl;
}
};
int main()
{
C c;
cout << "C::m_a的值是:" << c.C::m_a << endl;
cout << "B::m_a的值是:" << c.B::m_a << endl;
cout << "A::m_a的值是:" << c.B::A::m_a << endl;
c.C::func();
c.B::func();
c.B::A::func();
}
在一个例子:
基类:
派生类:
继承的特殊关系
派生类和基类之间有一些特殊关系。
- 可以把派生类对象赋值给基类对象(包括私有成员),但是,会舍弃非基类的成员。
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class A { // 基类
public:
int m_a=0;
private:
int m_b=0;
public:
// 显示基类A全部的成员。
void show() { cout << "A::show() m_a=" << m_a << ",m_b=" << m_b << endl; }
// 设置成员m_b的值。
void setb(int b) { m_b = b; }
};
class B :public A // 派生类
{
public:
int m_c=0;
// 显示派生类B全部的成员。
void show() { cout << "B::show() m_a=" << m_a << "m_c=" << m_c << endl; }
};
int main()
{
A a;
B b;
b.m_a = 10;
b.setb(20);
b.m_c = 30;
a.show();
a = b;
b.show();
// B b;
// A* a = &b;
// b.m_a = 10;
// b.setb(20); // 设置成员m_b的值。
// b.m_c = 30;
// b.show(); // 调用的是B类的show()函数。
// a->m_a = 11;
// a->setb(22); // 设置成员m_b的值。
// // a->m_c = 30;
// a->show(); // 调用的是A类的show()函数。
}
- 基类指针可以在不进行显式转换的情况下指向派生类对象。
- 基类引用可以在不进行显式转换的情况下引用派生类对象。
- 如果函数的形参是基类,实参可以用派生类。
基类指针或引用只能调用基类的方法,不能调用派生类的方法。
#include <iostream> // 包含头文件。
using namespace std; // 指定缺省的命名空间。
class A { // 基类
public:
int m_a=0;
private:
int m_b=0;
public:
// 显示基类A全部的成员。
void show() { cout << "A::show() m_a=" << m_a << ",m_b=" << m_b << endl; }
// 设置成员m_b的值。
void setb(int b) { m_b = b; }
};
class B :public A // 派生类
{
public:
int m_c=0;
// 显示派生类B全部的成员。
void show() { cout << "B::show() m_a=" << m_a << "m_c=" << m_c << endl; }
};
int main()
{
B b;
A* a = &b;
b.m_a = 10;
b.setb(20);
b.m_c = 30;
b.show();
a->m_a=10;
a->setb(20);
a->show();
// B b;
// A* a = &b;
// b.m_a = 10;
// b.setb(20); // 设置成员m_b的值。
// b.m_c = 30;
// b.show(); // 调用的是B类的show()函数。
// a->m_a = 11;
// a->setb(22); // 设置成员m_b的值。
// // a->m_c = 30;
// a->show(); // 调用的是A类的show()函数。
}