#include <iostream>
class A
{
public:
void a1(){
std::cout << "a1" << std::endl;
}
virtual void vt(){
std::cout << "a" << std::endl;
}
private:
void a2(){
std::cout << "a2" << std::endl;
}
protected:
void a3(){
std::cout << "a3" << std::endl;
}
};
class B : public A
{
public:
void b1(){
std::cout << "b1" << std::endl;
}
virtual void vt(){
std::cout << "b" << std::endl;
}
private:
void b2(){
std::cout << "b2" << std::endl;
}
protected:
void b3(){
std::cout << "a3" << std::endl;
}
};
int main()
{
B *pb = new B;
A *pA = pb;
pA->vt(); // 正确:输出为 b (多态性)
pA->a1(); // 正确:输出为 a1
// pA->a2(); // 错误:pA无权访问私有成员函数 a2
// pA->a3(); // 错误:pA无权访问保护成员函数 a3
// pA->b1(); // 错误:b1 不是 类A 的成员函数
// pA->b2(); // 错误:b2 不是 类A 的成员函数
// pA->b3(); // 错误:b3 不是 类A 的成员函数
std::cout << std::endl;
pb->vt(); // 正确:输出为 b (多态性)
pb->a1(); // 正确:输出为 a1
// pb->a2(); // 错误:pb无权访问基类的私有成员函数
// pb->a3(); // 错误:b无权访问基类的保护成员函数
pb->b1(); // 正确:输出为 b1
// pb->b2(); // 错误:pb无权访问自身的私有成员函数
// pb->b3(); // 错误:b无权访问自身的保护成员函数
B b;
A &rb = b;
std::cout << std::endl;
rb.vt(); // 正确:输出为 b (多态性)
rb.a1(); // 正确:输出为 a1
// rb.a2(); // 错误:rb无权访问私有成员函数
// rb.a3(); // 错误:pA无权访问保护成员函数 a3
// rb.b1(); // 错误:b1 不是 类A 的成员函数
// rb.b2(); // 错误:b2 不是 类A 的成员函数
// rb.b3(); // 错误:b3 不是 类A 的成员函数
std::cout << std::endl;
b.vt(); // 正确:输出为 b (多态性)
b.a1(); // 正确:输出为 a1
// b.a2(); // 错误:b无权访问基类的私有成员函数
// b.a3(); // 错误:b无权访问基类的保护成员函数
b.b1(); // 正确:输出为 b1
// b.b2(); // 错误:b无权访问自身的私有成员函数
// b.b3(); // 错误:b无权访问自身的保护成员函数
return 0;
}
结论:
1、对于派生类和基类的访问范围:
(1)派生类可以直接访问自身的公有成员函数和基类中的公有成员函数。
(2)私有成员变量、私有成员函数只能通过调用类中的公有成员函数来访问,不能通过对象名直接访问。派生类不能访问基类的私有成员函数。
(3)保护成员变量、保护成员函数也只能通过调用类中的公有成员函数来访问,不能通过对象名直接访问。派生类可以通过公有成员函数访问基类的保护成员函数。
2、关于指向派生类的基类指针和基类引用的访问范围:
(1)指向派生类的基类指针或者引用,其类型仍然属于基类类型,而不是派生类类型,尽管它指向的是派生类。其访问范围受其基类类型影响,因此只能访问基类中可以访问的类型。
(2)对于虚函数,使用指向派生类的基类指针或基类引用访问时,将会体现出多态性,调用的是实际上是派生类的对应函数。
(3)对于指向派生类的基类引用,虽然说引用通常是被引用对象的一个别名,但这里,基类引用的访问范围与被引用对象的访问范围明显是不一样的!
一句话这样总结:当基类类型的指针或引用使用派生类的对象时,它对虚函数的调用,实际上是调用了被指向对象类的函数。注意,取决于被指向对象。
当它对非虚函数调用时,会使用基类自身的函数。