2015-06-24 23 views
5

Tôi không hiểu tại sao việc gán một lớp dẫn xuất không gọi toán tử tương ứng của lớp cơ sở, nếu nó không tồn tại. Xem mã:Toán tử gán C++ trong lớp dẫn xuất

#include <iostream> 
using namespace std; 

class A{ 
protected: 
    void myWrite(){ 
    cout << " Base " <<endl; 
    } 
public: 
    double x,y; 
    A(): x{0},y{0}{}; 
    virtual A & operator=(double g){x=g;y=g;return *this;} 
    virtual ~A(){}; 
    virtual void doneit(){myWrite();} 
}; 


class B: public A{ 
protected: 
public: 
    B():A(){}; 
    virtual ~B(){}; 
    virtual void doneit(){myWrite();} 
}; 

int main() { 
    A jj; 
    B pp; 

    pp=0.0; 
    return 0; 
} 

Vì mã không biên dịch. Tất nhiên nếu tôi xác định một "toán tử =" cho B giống hệt nhau cho A, mọi thứ hoạt động, nhưng tại sao toán tử B "=" không được gọi theo mặc định nếu một trong lớp dẫn xuất không được định nghĩa ?? Bạn có thể giúp làm sáng tỏ vấn đề này không?

Trình biên dịch gcc cho biết ../src/tito.cpp:40:4: lỗi: không thể quá tải có thể '=' pp = 0,0; ~~^~~~ ../src/tito.cpp:28:7: lưu ý: hàm ứng cử viên (toán tử gán bản sao ngầm) không thể thực hiện được: không có chuyển đổi nào được biết từ 'double' thành 'const B' cho đối số thứ nhất loại B: công khai A { ^ 1 lỗi được tạo.

Bạn có thể giải thích lý do tại sao nó không hoạt động?

Trả lời

8

Nếu bạn không khai báo toán tử gán bản sao, trình biên dịch sẽ khai báo một cho bạn. Vì vậy, lớp học của bạn Bthực sự trông giống như:

class B : public A { 
public: 
    // explicit 
    B(); 
    virtual ~B(); 
    virtual void doneit(); 

    // implicit 
    B(const B&); 
    B& operator=(const B&); 
}; 

Các toán tử gán ngầm copy da các A::operator=(double) mà bạn đã viết, vì vậy nó là ứng cử viên duy nhất mà tra cứu tên sẽ tìm thấy. Tất nhiên, nó không phải là một ứng viên khả thi, vì double không thể chuyển đổi thành B, do đó có lỗi.

Để sử dụng các nhà điều hành A::operator=(double), bạn phải mang một cách rõ ràng nó vào phạm vi:

using A::operator=; 

Nhưng sau đó bạn sẽ không được giao bất kỳ phần B. Vì vậy, sẽ tốt hơn để rõ ràng hơn:

B& operator=(double g) { 
    // B stuff here 

    // A stuff 
    A::operator=(g); 

    return *this; 
} 
+1

Vâng, lý do chính là 'điều hành của cha mẹ mà = 'không gán một phần của đứa trẻ để ngầm sử dụng nó easilly có thể tạo các đối tượng bị hỏng. – StenSoft

+0

Cảm ơn bạn đã nhận xét rất hữu ích !! – Max

2

Toán tử gán bản sao của lớp dẫn xuất được khai báo ẩn của lớp cơ sở. Sử dụng sử dụng khai trong lớp được thừa kế theo cách sau

class B: public A{ 
protected: 
public: 
    using A::operator =;  
    B():A(){}; 
    virtual ~B(){}; 
    virtual void doneit(){myWrite();} 
}; 

cách tiếp cận khác là để redeclare toán tử gán ảo trong lớp có nguồn gốc

B & operator=(double g) { A::operator =(g) ;return *this;} 

Trong trường hợp này bạn có thể sử dụng đa hình. Ví dụ

#include <iostream> 

class A 
{ 
public: 
    double x,y; 
    A(): x{0}, y{0} {} 
    virtual A & operator =(double g){ x = g; y = g; return *this; } 
    virtual ~A(){} 
}; 


class B: public A 
{ 
public: 
    B() : A(){} 
    virtual B & operator =(double g) override { A::operator =(2 * g) ; return *this; } 
    virtual ~B(){} 
}; 

int main() 
{ 
    A a; 
    B b; 

    A *p = &a; 

    *p = 10; 

    std::cout << p->x << ' ' << p->y << std::endl; 

    p = &b; 

    *p = 10; 

    std::cout << p->x << ' ' << p->y << std::endl; 

    return 0; 
} 

Sản lượng chương trình là

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