2012-05-11 36 views
13

Theo sách C++ Primer, tác giả đã đề cập rằng chúng ta có thể chỉ định một hàm thành viên lớp làm bạn của một lớp khác, thay vì toàn bộ lớp (trang 634).Chỉ định một hàm thành viên của lớp làm bạn của một lớp khác?

Sau đó, tôi đã kiểm tra mã này:

class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 
class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 

Tôi chỉ muốn các FB() là bạn của lớp A, không phải là lớp toàn bộ B. Nhưng về mã sản xuất một lỗi: 'B' : is not a class or namespace name. (Tôi đang sử dụng Visual C++ 2005)

Trả lời

14

Hãy thử đặt định nghĩa B trước A:

class A; // forward declaration of A needed by B 

class B 
{ 
public: 
    // if these require full definition of A, then put body in implementation file 
    void fB(A& a); // Note: no body, unlike original. 
    void fB2(A& a); // no body. 
}; 

class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 

A cần định nghĩa đầy đủ của B. Tuy nhiên, B cần biết về A, nhưng không cần định nghĩa đầy đủ, vì vậy bạn cần khai báo chuyển tiếp A.

+0

Nhưng nếu trong FB (A & a) Tôi sử dụng một để truy cập biến trong Một ví dụ, a.variable; điều đó sẽ là bất hợp pháp vì A chưa được xác định. – ipkiss

+1

@ipkiss có, bởi vì sau đó bạn sẽ cần định nghĩa đầy đủ nếu bạn có trong khai báo lớp tiêu đề. Nhưng nếu bạn đã làm nó trong một tập tin thực hiện riêng biệt, bạn có thể bao gồm các tuyên bố đầy đủ của A. – juanchopanza

2

Để làm việc này, định nghĩa đầy đủ của B cần được biết trước định nghĩa A.

Vì vậy, về phía trước tuyên bố A, vì B không cần đầy đủ các loại, và chuyển đổi các định nghĩa xung quanh:

class A; 
class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 
class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 
0

trước tiên chuyển tiếp khai báo lớp A, để hiển thị ở định nghĩa lớp B. sau đó xác định lớp A có chứa một hàm người bạn từ lớp B.

0

Trước hết, trước tiên sử dụng một tên lớp cụ thể, bạn sẽ phải khai báo nó trước tiên. Vì vậy, bạn sẽ cần một tuyên bố về phía trước của lớp B khi bạn đang sử dụng nó trong lớp A trước khi lớp B đã được tuyên bố ban đầu.

Thứ hai, bạn sẽ cần định nghĩa các hàm (đang sử dụng các biến từ cả hai lớp - ở đây các hàm của bạn) sau khi cả hai lớp đã được xác định. Hoặc nếu không chúng tôi có thể gặp lỗi.

Ví dụ

#include<iostream> 

using namespace std; 

class alpha1; 

class alpha2 
{ 
    public: 

     void put_bata(int a,int b); 
}; 

void alpha2 :: put_bata(int a,int b) 
{ 
    alpha1 net; 

    net.roll=a; 

    net.id=b; 

    net.get_data(); 
} 

class alpha1 
{ 
    int roll; 

    int id; 

    public: 

     void get_data(void) 
     { 
      cout<<roll<<endl<<id<<endl; 
     } 

     friend void alpha2 :: put_bata(int a,int b); 
}; 

int main() 
{ 
    alpha2 gamma; 

    gamma.put_bata(5,6); 

    return 0; 
} 

sẽ cho chúng ta thấy lỗi như put_bata cố gắng truy cập cuộn và id trước khi chúng được định nghĩa ngay cả khi chúng tôi đã có một tuyên bố về phía trước của lớp nhưng mã đưa ra dưới đây sẽ chỉ hoạt động tốt.

#include<iostream> 

using namespace std; 

class alpha1; 

class alpha2 
{ 
    public: 

     void put_bata(int a,int b); 
}; 

class alpha1 
{ 
    int roll; 

    int id; 

    public: 

     void get_data(void) 
     { 
      cout<<roll<<endl<<id<<endl; 
     } 

     friend void alpha2 :: put_bata(int a,int b); 
}; 

void alpha2 :: put_bata(int a,int b) 
{ 
    alpha1 net; 

    net.roll=a; 

    net.id=b; 

    net.get_data(); 
} 


int main() 
{ 
    alpha2 gamma; 

    gamma.put_bata(5,6); 

    return 0; 
} 
0

@juanchopanza @ipkiss Về vấn đề mà bạn không thể truy cập các thành viên dữ liệu của A bên FB (A & a) vì A không được định nghĩa được nêu ra. Thay vì xác định nó trong một tệp riêng biệt và bao gồm nó, bạn có thể chỉ định hàm fB (A & a) sau định nghĩa lớp A sao cho fB (A & a) có thể xem các thành viên dữ liệu của A.

2

Khi trình biên dịch bắt đầu đọc mã (thường là từ trên) và nó gặp dòng này:

friend void B::fB(A& a);

Sau đó trình biên dịch không hiểu điều gì làm bạn có ý nghĩa bởi B:: này. Thậm chí nếu bạn đã định nghĩa lớp này sau trong mã nhưng trình biên dịch không biết điều đó.Vì vậy, nó thường là một tốt để thực hành để làm tờ khai trước của lớp học (class Name;) nếu định nghĩa cư trú sau này trong mã.

2

Khi trình biên dịch bắt đầu biên dịch mã (thường là từ trên) và nó gặp dòng này:

friend void B::fB(A& a); 
  1. vào thời điểm này, trình biên dịch không có ý tưởng về thông tin loại B nên nó ném một lỗi ('B': không phải là tên lớp hoặc không gian tên).
  2. bằng cách khai báo chuyển tiếp của lớp B, trình biên dịch biết về loại B là Lớp trước để khai báo thực tế với tất cả các thành viên.

  3. chạy bên dưới mã sau khi tờ khai phía trước của lớp B.

///////////////

class B; 
class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){}; 
}; 
class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 

Tuy nhiên lỗi !!!

vì khai báo chuyển tiếp chỉ là khai báo số nhận dạng mà lập trình viên chưa đưa ra định nghĩa đầy đủ. do đó trình biên dịch cần định nghĩa đầy đủ của B trước lớp A.

Lưu ý: lớp A phụ thuộc vào kiểu B và định nghĩa của B (tức là B :: fB) để tự khai báo chuyển tiếp. B cần phải xác định trước khi đến lớp A.

4 chạy mã này

////////

class B 
{ 
public: 
    void fB(A& a){}; 
    void fB2(A& a){}; 
}; 
class A 
{ 
public: 
    friend void B::fB(A& a); 
    void fA(){} 
}; 

Tuy nhiên lỗi !!!

vì chức năng thành viên lớp B FB & FB2 có đối số loại A nhưng trình biên dịch không có ý tưởng về thông tin loại A như vậy theo tờ khai phía trước của lớp A, chúng ta có thể để cho trình biên dịch biết về thông tin loại A. Lưu ý: lớp định nghĩa B chỉ phụ thuộc vào loại của A không phải là thành viên của A sao cho tờ khai chuyển tiếp của A bước quyết tâm 4.

  1. mã cuối cùng

////// //////////////////

class A; // forward declaration of A needed by B 
class B 
{ 
public: 
    void fB(A& a); 
}; 

class A 
{ 
    int i; 
public: 
    friend void fA(A& a); //specifying function fA as a friend of A, fA is not member function of A 
    friend void B::fB(A& a); //specifying B class member function fB as a friend of A 
}; 

// fA is Friend function of A 
void fA(A& a) 
{ 
    a.i = 11; // accessing and modifying Class A private member i 
    cout<<a.i<<endl; 
} 

// B::fB should be defined after class A definition only because this member function can access Class A members 
void B::fB(A& a) 
{ 
    a.i = 22; // accessing and modifying Class A private member i in Class B member function fB 
    cout<<a.i<<endl; 
} 

int main() 
{ 
    A a; 
    fA(a); // calling friend function of class A 

    B b; 
    b.fB(a); // calling B class member function fB, B:fB is friend of class A 

    return 0; 
} 

6 Bài tập:

// Cyclic dependency 
#include<iostream> 
using namespace std; 

class A; 

class B 
{ 
public: 
    void fB(A& a); 
    friend void A::fA(B& b); //specifying class A's member function fA as a friend of B 
}; 

class A 
{ 
    int i; 
public: 
    void fA(B& b); 
    friend void B::fB(A& a); //specifying class B's member function fB as a friend of A 
}; 

int main() 
{ 
    return 0; 
} 
+0

Vì vậy, làm thế nào để bạn giải quyết các bài tập? –

+0

@BrunoMartinez - Không có giải pháp hoàn hảo cho điều này vì cả hai đều phụ thuộc vào định nghĩa hoàn chỉnh của nhau theo chu kỳ. Ý định của tôi về cho trường hợp đặc biệt này là để làm nổi bật tầm quan trọng của các thực thể tách trong thiết kế phần mềm và để có được sự rõ ràng hơn về hàm Friend trong khi làm việc về điều này. Tôi đoán, bạn có thể đã biết rằng tùy chọn có thể cho việc này là tạo ra một hàm người bạn chung – SrinivasPaladugu

Các vấn đề liên quan