Đó là bởi vì việc tra cứu tên sẽ dừng lại nếu nó tìm thấy tên ở một trong các cơ sở của bạn. Nó sẽ không nhìn xa hơn ở các căn cứ khác. Hàm trong B phủ bóng hàm trong A. Bạn phải khai báo lại hàm của A trong phạm vi của B, để cả hai hàm đều hiển thị từ bên trong B và C:
class A
{
public:
void foo(string s){};
};
class B : public A
{
public:
int foo(int i){};
using A::foo;
};
class C : public B
{
public:
void bar()
{
string s;
foo(s);
}
};
Chỉnh sửa: Mô tả thực mà Tiêu chuẩn đưa ra là (từ 10,2 / 2):
Các bước sau đây xác định kết quả tra cứu tên trong phạm vi lớp, C. Đầu tiên, mọi khai báo cho tên trong lớp và trong mỗi đối tượng con của lớp cơ sở của nó đều được xem xét. Tên thành viên f trong một đối tượng con B ẩn tên thành viên f trong đối tượng con A nếu A là đối tượng con lớp cơ sở của B. Bất kỳ khai báo nào bị ẩn như vậy đều bị loại khỏi việc xem xét. Mỗi khai báo này được đưa vào bởi một khai báo sử dụng được coi là từ mỗi đối tượng con của C thuộc kiểu chứa khai báo được chỉ định bởi khai báo sử dụng.96) Nếu tập hợp khai báo kết quả không tất cả từ các đối tượng con cùng loại, hoặc tập hợp có thành viên không ổn định và bao gồm các thành viên từ các đối tượng con riêng biệt, sẽ có sự mơ hồ và chương trình không được định hình. Nếu không thì tập hợp đó là kết quả của việc tra cứu.
Nó có những điều sau đây để nói ở một nơi khác (ngay phía trên nó):
Đối với biểu thức id [ một cái gì đó như "foo" ], tra cứu tên bắt đầu trong phạm vi lớp của cái này; đối với id đủ điều kiện [ một cái gì đó như "A :: foo", A là mã định danh lồng nhau ], tra cứu tên bắt đầu trong phạm vi của mã định danh tên lồng nhau. Việc tra cứu tên diễn ra trước khi kiểm soát truy cập (3.4, khoản 11).
([...] do tôi đặt). Lưu ý rằng điều đó có nghĩa là ngay cả khi foo của bạn trong B là riêng tư, foo trong A vẫn sẽ không được tìm thấy (vì kiểm soát truy cập xảy ra sau đó).