2015-07-22 24 views
5

Tôi có một lớp cơ sở của một đối tượng hình học mà tôi sử dụng riêng của mình nhưng tôi cũng muốn kế thừa lớp vào một lớp khác, đó là loại phiên bản nâng cao của đối tượng vì chúng chia sẻ rất nhiều logic. Đối tượng cơ sở có một số phương thức tạo tĩnh (không thể sử dụng mới do xung đột đối số), tôi không muốn kế thừa các phương thức đó. Tôi có thể chỉ định bằng cách nào đó rằng những người không được thừa kế?Bạn có thể tạo một phương thức của một lớp không kế thừa được không?

EDIT: để bao gồm một ví dụ

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 

    static Banana CreateByHalfLength(float halfLength) { 
     return Banana(halfLength * 2); 
    } 
}; 

struct AdvancedBanana : Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 

Tôi không muốn AdvancedBanana :: CreateByHalfLength để tồn tại trong khi tôi muốn Banana :: CreateByHalfLength để tồn tại và có thể truy cập từ bên ngoài lớp học.

+0

Điều đó thực sự sẽ làm gì? Tôi đoán bạn muốn 'Derived :: constructBase (args, go, here)' không hoạt động? (nếu 'constructBase' là một phương thức tĩnh trên' Base', và 'Derived' mở rộng' Base') – immibis

+1

Nếu tôi để nó như vậy, nó sẽ tạo ra một cá thể đối tượng cơ bản. Không có hại trong nó thực sự, chỉ gây nhầm lẫn. Ngoài ra các phương thức được gọi là "CreateByXYZWLH" hoặc "CreateByRxRy" vv cũng được áp dụng cho lớp dẫn xuất để tôi có thể muốn sử dụng lại tên. – user81993

+0

@immibis Câu trả lời trông thẳng về phía tôi. Nếu tôi không sai, làm thế nào về việc sử dụng từ khóa riêng? – Nabin

Trả lời

3

Hãy thử điều này redclare chức năng như tư nhân ở trẻ em:.

#include <iostream> 
    class Banana { 
    public: 
     float length; 
     float getLenght(){ 
      return length; 
     } 
     void setLenght(float value){ 
      length = value; 
     } 
     Banana() {} 

     Banana(float length) { 
      this->length = length; 
     } 

     static Banana CreateByHalfLength(float halfLength) { 
      return Banana(halfLength * 2); 
     } 
    }; 

    class AdvancedBanana : public Banana { 
    public: 
     float bendAmt; 

     AdvancedBanana(float length, float bendAmt) { 
      this->length = length; this->bendAmt = bendAmt; 
     } 
    private: 
     static AdvancedBanana CreateByHalfLength(float halfLength); 

    }; 
    int main() 
    { 
    // work 
     Banana a(1); 
     a.CreateByHalfLength(1); 

    AdvancedBanana b(0,1); 
    //will fail 
    // b.CreateByHalfLength(1); 

    }; 
-1

Điều bạn đang nói hơi mơ hồ và ví dụ sẽ hữu ích. Đặc biệt khi bạn sử dụng từ tĩnh, và không rõ ngữ cảnh của nó là gì.

Bạn không thể dừng một lớp dẫn xuất thừa kế tất cả các phương thức của một lớp cơ sở. Điều tốt nhất bạn có thể làm là làm cho nó trở thành một thành viên không yêu cầu tham số đối tượng cơ bản. Sau đó, bạn sẽ phải downcast đối tượng trước khi gọi nhưng bạn vẫn có thể gọi nó.

Điều bạn cho là dường như vi phạm nguyên tắc thay thế Liskov. Có nghĩa là bạn nên suy nghĩ lại về thiết kế của mình.

Cũng thay vì B kế thừa từ A. Bạn có thể muốn có một lớp cơ sở Q mà từ đó cả A và B lấy được. [1]

[1] Q là một trò đùa, một số học giả kinh thánh nghĩ rằng có một số cuốn sách không phổ biến mà họ gọi là Q mà mỗi phúc âm được sao chép từ đó.

Chỉnh sửa: Bổ sung.

Với ví dụ, một số điều rõ ràng hơn. Hãy để tôi thực hiện một số chỉnh sửa cơ bản cho sự hiểu biết của bạn về C++. Bạn nói, bạn có một số phương pháp tạo tĩnh vì xung đột đối số. Tôi nghĩ rằng tốt hơn để nói quá tải không thể giải quyết các phương pháp xây dựng khác nhau. Câu trả lời cho điều đó rất đơn giản: mở rộng quá tải theo một trong hai cách. Sử dụng enums hoặc sử dụng các lớp học. Đầu tiên bạn có thể thấy trong suối gọi đọc/thêm/read-write suối loại bằng cách thêm ios :: ăn, vv

Trong trường hợp của bạn:

enum BCT {halfLength,fullLength,quarterLength ...}; 

Sau đó làm Banana tĩnh Tạo (kích thước phao , BCT type = fullLength) { công tắc (loại) { trường hợp fullLength: return Banana (size); trường hợp halfLength: return Banana (size * 2); trường hợp quýLength: return Banana (size * 4); ... }}

phiên bản thay thế là sử dụng các lớp học để phân biệt các loại tham số (Tôi tin rằng James Coplien gọi là những hình mẫu)

class FullLength 
class HalfLength 
class QuarterLength 

Sau đó:

static Banana Create(float length); // Full length 
static Banana Create(float halfLength, HalfLength &dummy); 
static Banana Create(float quarterlength, QuarterLength &dummy); 

mới các lớp không thêm gì ở trên đầu, nhưng loại bỏ sự mơ hồ quá tải. Tôi tin rằng boost/std :: filesystem sử dụng cách này cho các trình vòng lặp directorty.

Có nói rằng, sau khi bạn quyết định cách tạo các phiên bản, các trường hợp này không phải là thành viên tĩnh. Họ có thể là các nhà thầu bình thường và điều đó sẽ giải quyết vấn đề của bạn. Hầu hết. Bạn vẫn sẽ không thể ngăn AdvancedBanana thực hiện phương thức tạo nửa chiều dài nhưng trình coder sẽ biết rằng anh ta đang thực hiện nó.

Một lưu ý ngắn gọn về tĩnh học, hàm thành viên tĩnh là những người mà không truy cập vào con trỏ này hoặc những gì một số ngôn ngữ gọi tự, tức là họ không truy cập vào các thành viên của một trường hợp cụ thể. Trong thực tế trong preC++ 98 ngày, trước khi họ có thống kê, những gì mọi người đã làm là để làm một cái gì đó như: ((Banana *)NULL)->static_function(arguments);

Trong ví dụ của bạn, tốt hơn là sử dụng các nhà thầu ở nơi đầu tiên. các nhà xây dựng tĩnh tốt hơn còn lại cho những thứ như các nhà máy nơi chúng thực sự cần thiết.

Ngoài ra, trong phản hồi của Mido dòng: a.CreateByHalfLength(1); có thể hoặc không thể biên dịch, tôi sử dụng rất nhiều ngôn ngữ, đôi khi tôi bị lẫn lộn bởi những gì là bất hợp pháp: (nhưng là cho thấy suy nghĩ xấu. được Banana :: CreateByHalfLength (1); không phụ thuộc vào một thể hiện

1

Bạn chỉ có thể làm như thế này, sử dụng kế thừa tư nhân cho AdvancedBanana.

#include <stdio.h> 

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 

    static Banana CreateByHalfLength(float halfLength) { 
     return Banana(halfLength * 2); 
    } 
}; 

struct AdvancedBanana : private Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 


int main() 
{ 
    Banana b; 
    b.CreateByHalfLength(1); 

    AdvancedBanana bb(1, 2); 
    //bb.CreateByHalfLength(2); 

    return 0; 
} 

AdvancedBanana :: CreateByHalfLength nên tồn tại, nếu bạn muốn Banana :: CreateByHalfLength để tồn tại và có thể truy cập từ bên ngoài lớp. Và đây cũng không phải là một giải pháp tốt.

Trên một cách khác, tôi được đề xuất, để thiết kế hai hoặc nhiều lớp học hoặc lấy các chức năng ra khỏi Chuối, cho nhu cầu của bạn. Nó sẽ là một cái gì đó như thế này.

#include <stdio.h> 

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 
}; 

static Banana CreateByHalfLength(float halfLength) { 
    return Banana(halfLength * 2); 
} 

struct AdvancedBanana : private Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 


int main() 
{ 
    Banana b = CreateByHalfLength(1); 
    AdvancedBanana bb(1, 2); 
    //bb.CreateByHalfLength(2); 

    return 0; 
} 
1

Nếu bạn muốn tự động hạn chế các lớp thừa kế để quá tải static Banana CreateByHalfLength(float halfLength); sau đó một cách rất nhanh chóng là để đóng gói chức năng bên trong một phương pháp virtual final.

ví dụ:

struct Banana { 
    ... 
    // Create a namesake wrapper for the `static` function and make it final 
    virtual 
    Banana CreateByHalfLength(float halfLength) final { 
    return CreateByHalfLengthImpl(halfLength); 
    } 

    static Banana CreateByHalfLengthImpl(float halfLength) { 
    return Banana(halfLength * 2); 
    } 
}; 

Với sự sắp xếp này, bây giờ bất kỳ lớp được thừa kế sẽ không thể tạo ra một chức năng tương tự static hoặc phi static.
Here is a demo.

Hạn chế của phương pháp này là bạn đang thêm một chức năng trên không là virtual cũng như được gọi với một đối tượng không sử dụng.

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