Lớp con có kế thừa biến private từ lớp cha không?

Cho mình hỏi là theo mình biết thì lớp con k kế thừa private từ lớp cha, nhưng tại sao nếu có một hàm public từ lớp cha, lớp đó trả về 1 biến private của lớp đó.

thì lớp con cũng có hàm đó, cũng trả về được biến private đó.

class A
{
    private String a;
    A(String a)
   {
      this.a = a;
   }

    public String geta() { return a; }
}
class B extends A
{
    public Hippo(String name) 
    {
        super(name);
    }
}

B b = new B("xxx");
1 Like

Nó trả về bản sao của a chứ nó không trả về a.

2 Likes
  1. Khi thuộc tính của lớp cha là private thì lớp con thể truy cập trực tiếp vào thuộc tính đó để gán, để lấy giá trị.
    Ví dụ: b.a --> không được.

  2. Lớp con phải qua 1 hàm public của lớp cha để truy cập trực tiếp vào thuộc tính đó của lớp cha.
    ví dụ:s tring name = b. geta().

Lợi ích: giúp cho việc kiểm soát giá trị đầu vào và đầu ra của thuộc tính đó.

3 Likes

Hi Trâu Gia Gia.
Có. Có nên không còn gì để nói nữa.

P/S Dựa vào đâu bạn biết là không ?

1 Like

Đó là với string hoặc primitive thôi, chứ nó vẫn trả về a đấy anh.

1 Like

trong sách nói thế mà, nó k kế thừa thành phần private

Không phải là không kế thừa, mà phải là không truy cập được. Nếu muốn truy cập nó thì bạn phải dùng 1 phương thức public (getter hay setter,...) của lớp cha.

Nó không kế thừa, vì không truy xuất bằng cách bình thường trong lớp con được, đơn giản là vậy.

NHƯNG
Trong bộ nhớ (của lớp con) vẫn tồn tại giá trị đó, chỉ là không truy xuất được mà thôi.


“Cách bình thường”

Tức cách gọi thông thường lớp_con.phương_thức() hoặc lớp_con.tên_trường


“Cách KHÔNG bình thường”

Phản chiếu - Reflection java.lang.reflect

2 Likes

Đây nhé :

#include <iostream>
class Parent{
public:
int getData(){ return _Data;}
int addressOfData(){
std::<<"Address of _RawData : " << &_Data <<std::endl;
}

private:
int _Data=0;
};

class Child:public Parent{
};

int main(int argc, char *argv[]){
Child* b = new Child();
b->addressOfData();
int ret = b->getData();
std::cout<<"Address of _Return : "<< &ret<<std::endl;
return 0;

}

Kết quả:
image

1 Like

Dùng 1 biến khác để lưu giá trị của _Data thì dĩ nhiên là 2 địa chỉ đó phải khác nhau rồi, ret đâu có phải là _Data

Thế thì mình mới nói nó là bản copy.

Bạn thử change 2 cái này xem:

int& ret = int& GetData();

Nếu nó chỉ là bản copy như bạn nói thì sẽ ko có khái niệm setter (và cả getter). Vì bản copy thì đâu thể change được giá trị thực của biến đó

2 Likes

Bạn đang chỉ nhìn vào kết quả mà đánh giá sai bản chất rồi. Khi bạn khai báo int ret thì bạn tạo ra một vùng nhớ mới để lưu trữ bản sao của dữ liệu. Cụ thể ở đây là số primitive type int. Cái mà bạn in ra sau này là địa chỉ ô nhớ của một biến nằm ngoài class. So sánh vậy mình nghĩ là khập khiễng.

2 Likes

Không phải là hiểu sai bản chất. Mà cơ bản ngẫm đi ngẫm lại thì đúng là nó hơi lạc vấn đề :smile:

1 Like

Anh Dương hiểu sai vấn đề rồi. Trong Java mình không có “địa chỉ”, nên mình chỉ có thể trả về đối tượng thôi, đối tượng lớp con vẫn có trường đó, nhưng không truy cập được. Trong hình, gson truy cập vào object thông qua reflection.

Với cả anh code int ret = ... mà không gán &ret thì &ret đâu có thay đổi đâu, anh gán ret bằng cái gì thì anh in ra &ret vẫn thế, lỗi đâu phải do kế thừa, do anh code sai đấy chứ :joy_cat:

1 Like

À các bạn đang nhầm nhé. Thực ra mình chỉ phủ định ý của #1 là hàm geta() của lớp con trả về a của lớp cha.
Thực ra nó không trả về a mà trả về bản sao của a và lưu vào ret.
Còn thực tế thì biến private của lớp cha vẫn đi cùng lớp con nhưng sẽ bị ẩn đi. Kiểm tra kích thước class là biết thôi.

Trong Java, C# không còn khái niệm con trỏ và do đó mất khái niệm địa chỉ. Tuy nhiên 2 loại biến sinh ra từ struct và class sẽ return khác nhau nhé.
Biến từ struct hoặc biến nguyên thủy khi return sẽ trả về bản sao.
Biến từ class sẽ trả về reference (gần giống con trỏ C++).

1 Like

em đang nói về java mà, sao bác lại code c++

Theo mình nghĩ, biến không thuộc đối tượng mà thuộc về lớp, còn dữ liệu thuộc về đối tượng. Khi ta gọi phương thức, cái ta thu được là dữ liệu (đối tượng hoặc giá trị) chứ không phải là biến, nên việc biến được khai báo quyền truy cập như thế nào không ảnh hưởng đến getter của biến đó hoạt động như thế nào.

@Duong_Act: Trong Java không có struct. Và method trả về dữ liệu chứ không trả về ref. Chỉ có thể gán dữ liệu vào ref: Ví dụ:

ref = a.x();//Được, vì ref là refernce, còn a.x() là dữ liệu
ref = new B();//Được, vì ref là reference, còn new B() là dữ liệu
a.x() = new B();//Lỗi cú pháp, vì a.x() là dữ liệu nên không thể gán

Nếu anh muốn hàm trả về địa chỉ, anh phải trả về địa chỉ (return &(getData());) hoặc cái gì đó tương tự, không phải là cú pháp như anh ví dụ ở trên. Vì anh đã sử dụng một con biến trung gian là ret làm sai lệch kết quả.

Với cả kể cả với việc anh gán ret = a.getData(); anh có chắc chắn là getData() trả về bản sao của _Data không, hay chính phép toán = mới tạo bản sao của a.getData()? Vì trong Java, các biến primitive thực ra đều được tạo sẵn trên pool của máy ảo, và return chỉ là trỏ đến các đối tượng tạo sẵn đó thôi, liệu C++ có như vậy?

Hi Trâu Gia Gia.

  1. Có thể trong ngữ cảnh đó có nghĩa là không truy xuất trực tiếp được thôi.
  2. Khái niện kế thừa và chỉ thị truy cập (public, private) là hai khái niệm riễng rẽ. Sẽ không có chuyện không kế thừa các thuộc tính private vì khi đó các phương thức public được kế thừa có sử dụng biến private sẽ không làm việc.

P/S Biểu hiện bên ngoài không phản ánh hết bản chất bên trong.

2 Likes

Có thể dùng cách này:

Đặt access modifier của thuộc tính a là protected thay vì private.

protected cho phép class con truy cập trực tiếp vào thuộc thính của lớp cha. Thêm vào đó, proteced cũng không cho truy cập từ ngoài vào. Vì vậy vẫn đảm bảo tính bảo mật nhé

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?