почему унаследованные функции изменяют переменные-члены в базовом классе, а не на одноименные, называемые объектами - PullRequest
0 голосов
/ 08 июня 2018

Я хочу спросить, почему функция setX здесь устанавливает переменную-член x в классе A, а не переменную-член x в классе D, даже если я вызываю функцию setX через объект D?Как компилятор сделал это?

#include<iostream>
using namespace std;

class A
{

public:
    int x;
    A() { cout << "A cons" << endl; }
    void setX(int i){ x = i; cout << "setxA" << endl; }
    void print() { cout << x; }
};

class B : public A
{
public:
    int x =30;
    B() { cout << "B cons" << endl;  }
};



class D : public B {
public:
    D() {
        cout << "D cons" << endl;

    }
    void func() {
        setX(10);
        cout << x << endl;
        cout << B::x << endl;
        cout << A::x << endl;


    }
};

int main()
{
    D d;
    d.func();
    return 0;
}

выход из этого кода 30 30 10

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

Это называется скрытием имени.И A, и B имеют члена x и , оба члена всегда существуют (вы просто не можете получить к ним одинаковый доступ).A знает о своем члене x, поэтому функция setX устанавливает именно этот член A::xB вы определяете другой x, который скрывает A::x.Это означает, что если вы выполните

B obj;
obj.x = 10;

или

D obj;
obj.x = 10;

, вы получите доступ к B::x оба раза (поскольку B ниже в иерархии наследования и поэтому скрывает A::x).

Вот пример того, как вы все еще можете получить доступ к A::x, используя различные приведения.

#include <iostream>

struct A {
    int x = 0;
    void setX(int i) { x = i; }
};

struct B : A {
    int x = 20;
};

int main()
{
    B obj;
    A castToA = static_cast<A>(obj);
    A* castToAPtr = reinterpret_cast<A*>(&obj);

    std::cout 
        << "access via B:        " << obj.x << "\n"
        << "access via A:         " << castToA.x << "\n"
        << "access via A*:        " << castToAPtr->x << "\n"
        << "access via B::(A::x): " << obj.A::x << "\n\n";


    obj.setX(100);
    std::cout << "set x to 100\n\n";

    std::cout 
        << "access via B:        " << obj.x << "\n"
        << "access via A:         " << castToA.x << "\n"
        << "access via A*:        " << castToAPtr->x << "\n"
        << "access via B::(A::x): " << obj.A::x << "\n\n";

    return 0;
}

, который дает вывод:

access via B:       20
access via A:       0
access via A*:      0
access via B::A::x: 0

set x to 100

access via B:       20
access via A:       0
access via A*:      100
access via B::A::x: 100
0 голосов
/ 08 июня 2018

У вашего класса B есть x, а также у A есть X. Таким образом, у вас есть два x в B!Таким образом, вы можете удалить x из вашего класса B?

Если вам нужны оба, вы можете получить к ним доступ с помощью

A :: x или B :: x внутри метода B, который вы уже использовали.did.

Таким образом, у вашего класса D есть и x, и вызов setX вызывает метод setX для A. Как и в D, вы видите x из B, который скрывает ваш x от A, все работает, как и ожидалось.

Ваш метод A :: setX не знал, что вы потом наследуете от него.Если вы хотите переопределить метод, B имеет собственный B :: setX, который затем будет также использоваться в D.

Пример того, как переопределить метод и получить доступ к параметру в производном классе:

class A
{
    public:
        int x;    // A::x 
        int y = 40; // A::y

        // this function only knows about A::x
        void setX(int i){ x = i; cout << "setxA" << endl; }
        void setY(int i){ y = i; cout << "setyA" << endl; }
};

class B : public A
{
    public:
        int x =30; // this x ( B::x) hide A::x
        int y =50; // this y hides also A::y

        // now we override setY from A ( hiding setY from A! )
        void setY(int i){ y = i; cout << "setyB" << endl; }

};



class D : public B {
    public:
        void func() {
            setX(10);   // Calls A::setX, as A::setX only knows about
                        // A::x it will access A::x
            cout << "X" << std::endl;
            cout << x << endl;
            cout << B::x << endl;
            cout << A::x << endl;

            setY(90);
            cout << "Y" << std::endl;
            cout << y << endl;
            cout << B::y << endl;
            cout << A::y << endl;
        }
};

int main()
{
    D d;
    d.func();
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...