基类中this指针和派生类对象的关系,同名隐藏原则和作用域的示例

本文探讨了在C++中,基类的this指针如何在派生类对象中工作,特别是在单例模式下,如何通过基类的getInstance()方法获取派生类的实例。文章通过分析单例模式的实现,揭示了在基类构造函数中,this指针实际上指向的是派生类的对象。同时,文章强调了在基类中使用this指针调用成员时,对于普通成员和虚函数的不同行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.  事情的由来

最近在分析cocos2d-x启动代码的时候,不小心看到单例的程序


    //定义一个app对象  
    AppDelegate app;
 
    //执行app对象的run函数。进入帧循环  
    Application::getInstance()->run();


AppDelegate 是Application的子类,AppDelegate 是一个单例的模式,但是通过父类Application::getInstance()获取AppDelegate的单例指针,

父类怎么知道子类对象的指针呢?原来是在Application的构造函数中通过this指针记录下来,但是在定义派生类对象的时候,

底层调用父类构造函数的时候,父类构造函数this指针就是执行派生类对象吗?我当时没反应回来,后来咀嚼几次终于想明白了。


class A
{
public:
A(){}
};


class B:public A
{
public:
B(){}
};





当我们定义对象
B myb;
这个时候编译器会给对象myb分配内存,还会调用B和他的基类的构造函数,我们都知道编译器成员函数做转换,添加this形参
这个时候我们的A的构造函数变为
A(A * this){}
调用构造函数就变为:myb.A(&myb)
所以在基类中的this指针自然而然就是指向调用它的对象了也就是派生类myb对象。


2. 结论

    当我们在基类中使用this指针调用成员的时候,有什么不一样的地方呢?

    主要是普通的同名成员和虚函数的时候不一样,直接上代码吧


#include<iostream>
using namespace std;
class A
{
public:
    A() {
        x = 10;
    }
    void testcallvalue()
    {
        //这里调用的是A中的x
        cout<<this->x<<endl;
    }

    void testcallvirtualfun()
    {
        //这里调用的是B中的vrfun函数
        this->vrfun();
    }


    void virtual vrfun(){
        cout<<"A()"<<endl;
    }

    int x;
};


class B:public A
{
public:
    B() {
        x = 20;
    }
    void virtual vrfun(){
       cout<<"B()"<<endl;
    }
    int x;
};


int main()
{
    B myb;
    //========================================
    //同名成员的测试
    //直接通过对象调用里面的同名数据成员
    cout<<myb.x<<endl;//20 这里调用的是B中定义的x
    //直接通过对象调用里面的同名数据成员
    myb.testcallvalue();//10
    //========================================
    myb.testcallvirtualfun();//B()
}






<think>好的,我现在需要帮助用户设计一个包含虚基类的C++继承体系,涉及Person、Student、TeacherTAssistant类。首先,用户的问题是关于虚基类的使用,所以我需要回忆一下虚基类的作用,主要是解决多重继承中的菱形继承问题,避免数据成员的重复继承。 根据用户提供的引用,特别是引用[4]提到了虚基类的构造函数初始化方式,所以需要注意在派生类中如何正确初始化虚基类。用户提到的类包括Person作为基类,StudentTeacher可能作为Person的直接派生类,而TAssistant可能同时继承StudentTeacher,形成菱形结构,这时候就需要虚继承。 接下来,我需要构建类的层次结构。Person作为虚基类,StudentTeacher虚继承Person,然后TAssistant继承StudentTeacher。这样,TAssistant只会包含一份Person的成员,避免重复。 然后,考虑各个类的成员变量函数。Person可能有姓名年龄,Student有学号,Teacher有工号,TAssistant可能有部门。每个类都需要构造函数,并且显示初始化虚基类。例如,StudentTeacher的构造函数需要调用Person的构造函数,而TAssistant在构造时需要同时初始化Student、Teacher基类Person。 在代码示例中,要展示如何正确使用虚继承,包括构造函数的初始化列表。同时,需要创建对象并调用成员函数,以展示继承关系基类的作用。例如,创建TAssistant对象后,调用display方法,应正确显示所有基类的属性,而不会出现数据重复。 还需要注意成员函数的覆盖隐藏问题,引用[1]提到派生类同名成员会隐藏基类的成员,所以如果Person有display方法,派生类需要覆盖或正确调用基类的方法,使用作用域运算符来避免隐藏。 最后,验证代码的正确性,确保没有二义性,并且虚基类的初始化正确。同时,生成相关问题,帮助用户进一步理解虚基类多重继承的相关问题。</think>### C++虚基类继承体系设计(Person/Student/Teacher/TAssistant) #### 继承关系设计 采用虚基类解决菱形继承问题: ``` Person(虚基类) ▲ ╱ ╲ 虚继承 虚继承 ╱ ╲ Student Teacher ╲ ╱ TAssistant ``` #### 类定义与实现 ```cpp #include <iostream> #include <string> using namespace std; class Person { protected: string name; int age; public: Person(string n, int a) : name(n), age(a) {} virtual void display() { // 虚函数实现多态 cout << "Name: " << name << "\nAge: " << age << endl; } }; class Student : virtual public Person { // 虚继承 protected: string student_id; public: Student(string n, int a, string sid) : Person(n, a), student_id(sid) {} void display() override { Person::display(); cout << "Student ID: " << student_id << endl; } }; class Teacher : virtual public Person { // 虚继承 protected: string teacher_id; public: Teacher(string n, int a, string tid) : Person(n, a), teacher_id(tid) {} void display() override { Person::display(); cout << "Teacher ID: " << teacher_id << endl; } }; class TAssistant : public Student, public Teacher { private: string department; public: // 必须直接初始化虚基类 TAssistant(string n, int a, string sid, string tid, string dept) : Person(n, a), Student(n, a, sid), Teacher(n, a, tid), department(dept) {} void display() override { Person::display(); cout << "Student ID: " << student_id << endl; cout << "Teacher ID: " << teacher_id << endl; cout << "Department: " << department << endl; } }; ``` #### 功能验证 ```cpp int main() { Person p("Alice", 30); Student s("Bob", 20, "S2023001"); Teacher t("Charlie", 40, "T1001"); TAssistant ta("David", 25, "S2023002", "T1002", "Computer Science"); cout << "=== Person ===" << endl; p.display(); cout << "\n=== Student ===" << endl; s.display(); cout << "\n=== Teacher ===" << endl; t.display(); cout << "\n=== Teaching Assistant ===" << endl; ta.display(); // 验证指针转换 Person* ptr = &ta; cout << "\n=== Virtual function through base pointer ===" << endl; ptr->display(); // 正确调用TAssistant::display() } ``` #### 关键特性验证 1. **虚继承效果**:TAssistant对象只包含一个Person子对象 2. **构造函数链**:必须直接初始化虚基类[^4] 3. **多态行为**:通过基类指针正确调用派生类方法[^2] 4. **内存布局**:使用`sizeof`运算符验证对象大小 #### 输出示例 ``` === Person === Name: Alice Age: 30 === Student === Name: Bob Age: 20 Student ID: S2023001 === Teacher === Name: Charlie Age: 40 Teacher ID: T1001 === Teaching Assistant === Name: David Age: 25 Student ID: S2023002 Teacher ID: T1002 Department: Computer Science === Virtual function through base pointer === Name: David Age: 25 Student ID: S2023002 Teacher ID: T1002 Department: Computer Science ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值