当调用派生类对象时,为什么`this`无法从基类方法访问派生类成员

时间:2013-08-08 13:00:37

标签: c++ inheritance

This指针在非const成员函数中的类型为ClassName

 class Base
 {
   public:
     void get()
     {
       //this->put(); Why can't I call back a derived class method eventhough 
                       **this** is pointing to derived class object.
     }
 };

 class derived: public Base
 {
   public:
   void put()
   {
    // do somthing.
   }
 };

 int main()
 {
  derived d;
  //d.get();
  d.put();
  return 0;
 }

如果我在两个函数中打印this指针的值都是相同的,表明它是为派生类对象调用的。此处this指针类型也是derived *

另据我的理解如果您在调用方法时有pointer对象,那么您只需指向整个{{1}中存在该方法的offset object layout 1}}从address中的pointer开始到object

但是,如果我在derived类方法中拥有start的{​​{1}}地址,为什么我无法偏移到(derived)object类方法。

由于上述理解,我无法理解为什么我不能这样做。我错过了一些非常基本的东西。

6 个答案:

答案 0 :(得分:7)

让我们假设你是一个编译器。现在你看到这个类:

class foo
{
    void bar() { this->xyz(); }
};

你做什么的?您抱怨您不知道xyz是什么,并且它肯定不是foo的成员函数。你不去寻找其他类并检查它们是否可以派生自foo并声明这个函数 - 它只能反过来。

反过来意味着您必须声明希望派生类实现的方法的签名:

class foo
{
    void bar() { this->xyz(); }
    virtual void xyz() = 0;
};

突然,这是有效的,但现在你不能再创建一个foo的实例了:每个具有纯虚方法的类都是一个抽象类。

但请注意, 适用于模板:

template <typename T>
class foo
{
    void bar() { t.xyz(); }
    T t;
};

因为每个模板都是在编译时实例化的,所以你不会看到上面的模板,而是在例如foo<xyz_class>可能会提供这样的功能。

答案 1 :(得分:5)

您必须将方法put()声明为虚拟。

class Base
{
public:
     virtual void put() = 0;
     void get()
     {
       //this->put(); Why can't I call back a derived class method eventhough 
                       **this** is pointing to derived class object.
     }
};

class derived: public Base
{
public:
    void put()
    {
    // do somthing.
    }
};

int main()
{
    derived d;
    //d.get();
    d.put();
    return 0;
}

答案 2 :(得分:5)

Me:当编译器编译Base :: get函数时,它看不到Derived :: put函数。

你:Derived ::不是放在同一个文件中吗?为什么编译器不能看到它?

我:如果有人在4年之后定义的Derived1 :: putttttt从另一个文件中的Base派生怎么办?

你:mm,也许我明白了。

答案 3 :(得分:2)

Base不知道您只是将它用作Derived对象的一部分;通常,可能有许多不同的派生类,只有一个或部分可能有put()。怎么可以编译Base呢?

当你有一个指向Base对象的Derived指针时,你可以投射它以获得指向Derived的指针,并以这种方式调用方法:

Base* b = new Derived;
dynamic_cast<Derived*>(b)-> put();

如果需要,类实际上可以将this强制转换为派生实例ponter:

dynamic_cast<Derived*>(this)-> put();

答案 4 :(得分:1)

考虑一下你在基类中编写了this->put()方法,在编译期间编译器会检查同一个类中的put()函数,因为你没有这样的,它会显示编译时错误

答案 5 :(得分:1)

您发布的代码将无法编译,因为编译器在编译derived的代码时不知道class Base类是什么。 this指针是一个指针,它隐式传递给类的每个非静态成员函数,该函数如何访问它的实例的成员属性。在Base类成员函数this中,类型为Base *const成员函数中,它将具有const Base *类型。

此外,this是非l值,表示您无法为其赋值。

以下是关于this指针的C ++标准:

  

9.3.2这个指针

     

在非静态(9.3)成员函数的主体中,关键字this是一个值为prvalue的表达式   是调用该函数的对象的地址。这个类型在一个成员函数中   X类是X *。如果成员函数声明为const,则其类型为const X *,如果是成员   函数声明为volatile,其类型为volatile X *,如果声明了成员函数   const volatile,这个类型是const volatile X *。

现在,在你的问题中做你想做的事情,以下编译

#include <iostream>
class Base
{
   public:
     void get();
};


class derived: public Base
{
   public:
   void put()
   {
        std::cout << "This is a bad idea" << std::endl;

   }
};


void Base::get()
{
    //compiler knows what dervied class is
    static_cast<derived *>(this)->put();  
}


 int main()
 {
    derived d;
    d.get();

    return 0;
 }

输出为:This is a bad idea

我建议使用虚拟功能或模板来获得所需的行为。