2016-09-02 13 views
5

Trong hiệu quả hơn C++, một điểm thú vị được đưa ra là sự pha trộn của mảng và đa hình là một ý tưởng tồi. Đối với ví dụ:Cảnh báo biên dịch cho mảng hỗn hợp và đa hình

class Base { 
    public: 
    Base(int y) : a(y) {} 
    int a; 
}; 

class D : public Base { 
    public: 
    D(int w, int y) : Base(y), c(w) {} 
    int c; 
}; 

std::ostream& operator<<(std::ostream& os, const Base &obj) 
{ 
    os << obj.a << std::endl; 
    return os; 
} 

// This function will work perfectly well if i pass in a `Base` array, 
// but if i pass in `D` array we are going to run into some problems. 
// Namely that `arr[i+1] = &arr[i] + sizeof(Base)` will not progress 
// the array correctly for a `D` array. 
void printArray(const Base arr[]) { 
    for (int i = 0; i < 5; ++i) { 
     std::cout << arr[i]; 
    } 
} 

int main() { 
    D arr[5] = { D(0, 10), D(1, 11), D(2, 12), D(3, 13), D(4, 14)}; 
    printArray(arr); // This compiles without complaint! I understand that the 
        // conversion is legal, but it seems like a warning 
        // about this would be a good idea. 
} 

Lưu ý: Tôi biết đây là thiết kế xấu nhưng là để minh họa cho một điểm. Vấn đề ở đây là khi trộn hai cái này theo cách tôi có ở trên, khi chúng ta lặp qua mảng để in, chúng ta sẽ không tiến hành phần tử của mảng theo đúng số lượng (tức là chúng ta di chuyển bởi sizeof(Base) thay vì sizeof(D)). Điều này dẫn đến kết quả:

10 
0 
11 
1 
12 

[Live example.]

(Và tôi đang đoán rằng gọi operator<< như thế này có lẽ là UB).

Khi biên dịch với g++ -std=c++1y -Wall -Weffc++ -pedantic main.cpp Tôi không nhận được cảnh báo hoặc lỗi.

  1. Có cờ trình biên dịch mà tôi có thể bật cho biết cảnh báo trong trường hợp này không?
  2. Nếu không, tại sao không?
+0

Vâng, câu trả lời cho '2)' là "cảnh báo" không bắt buộc đối với trình biên dịch để triển khai. Bạn có thể yêu cầu những người triển khai g ++ thêm một cảnh báo như vậy (nếu nó không tồn tại), nhưng chúng không bị ép buộc làm như vậy theo bất kỳ tiêu chuẩn nào. – PaulMcKenzie

+1

@PaulMcKenzie, đúng, nhưng GCC đi trên và xa hơn với cảnh báo của họ, tôi tự hỏi nếu có một khó khăn kỹ thuật trong việc phát hiện này? –

+0

Bạn phải yêu cầu các kỹ sư tổng hợp trình biên dịch. Có câu trả lời có thể là bất cứ nơi nào từ "đó là một ý tưởng tốt" để "chúng tôi không có thời gian" để "nó đã tồn tại". – PaulMcKenzie

Trả lời

1

void printArray(const Base arr[]) tương đương với void printArray(const Base* arr).

Đó là hợp pháp để chuyển con trỏ thuộc loại D đến hàm có tham số thuộc loại const Base*. Vì vậy trình biên dịch sẽ không đưa ra bất kỳ cảnh báo nào.

+1

Trình biên dịch được phép đưa ra cảnh báo cho các cấu trúc pháp lý. – jaggedSpire

+0

Tôi biết rằng đó là hành vi pháp lý, vì vậy là 'int arr [5]; arr [6] = 10', chúng tôi nhận được cảnh báo cho điều đó. –

+0

@Ben Giả sử 'printArray' được định nghĩa trong thư viện thứ ba và không có hàm gọi để chuyển con trỏ kiểu' D' tới 'printArray' trong thư viện đó. Trình biên dịch sẽ không phàn nàn gì cả. Tuy nhiên, khi ai đó sử dụng thư viện và chuyển một con trỏ kiểu 'D' tới' printArray'. Tôi không nghĩ rằng nó là một ý tưởng tốt cho trình biên dịch để kiểm tra việc thực hiện 'printArary' trong thư viện thứ ba, để xem liệu' printArray' có yêu cầu một mảng kiểu 'Base' hay không. –

-1

FYI, pha trộn các mảng và đa hình có thể được thực hiện nếu đa hình được cung cấp như một chi tiết thi hành một lớp xử lý:

#include <iostream> 
#include <vector> 

// a handle which will happily own any class which implements the concept 
struct Thing 
{ 
    struct concept 
    { 
     virtual void sayHello() const = 0; 
     virtual ~concept() = default; 
    }; 

    Thing(std::unique_ptr<concept> ptr) : _impl(std::move(ptr)) {} 

    void sayHello() const { _impl->sayHello(); } 

    std::unique_ptr<concept> _impl; 
}; 

struct thing_a : Thing::concept 
{ 
    void sayHello() const override { std::cout << "hello from A\n"; } 
}; 

struct thing_b : Thing::concept 
{ 
    void sayHello() const override { std::cout << "hello from B\n"; } 
}; 

int main() 
{ 
    std::vector<Thing> things; 

    things.emplace_back(std::make_unique<thing_a>()); 
    things.emplace_back(std::make_unique<thing_b>()); 

    for (const auto& t : things) { t.sayHello(); } 
} 

đầu ra mong đợi:

hello from A 
hello from B 
+2

Làm cách nào để trả lời câu hỏi này? – Barry

+1

@Barry Tôi nghĩ mục đích của trang web này là trả lời các câu hỏi * và * để giáo dục. Thực tế là tính đa hình có thể tương thích với ngăn chứa vector nếu được thực hiện một cách an toàn. Đây là một trong những cách để làm điều đó một cách an toàn. Câu trả lời nằm trong mạch của giáo dục. –

2

Một trình biên dịch có thể làm được rất nhiều phân tích tĩnh và có thể biết rằng con trỏ arr trong hàm được sử dụng làm mảng có kết quả không mong muốn. Tuy nhiên, làm chậm và sử dụng nhiều bộ nhớ hơn, và các lập trình viên nói chung thiếu kiên nhẫn và muốn biên dịch của họ được thực hiện càng nhanh càng tốt bằng cách sử dụng càng ít tài nguyên càng tốt. Do đó, hầu hết các trình biên dịch chỉ thực hiện các phân tích tĩnh tương đối nhanh chóng và dễ dàng, để lại công việc khó khăn cho các máy phân tích tĩnh chuyên dụng.

+0

Vì vậy, tôi giả sử bạn nghĩ rằng câu trả lời cho 1) là không. –

+0

@Ben Có lẽ là không. Nếu tài liệu không đề cập đến bất kỳ cảnh báo nào như vậy, thì cách duy nhất để biết chắc chắn là lấy nguồn (nếu có) và đọc nó. :) –

+0

Tôi không thực sự mua các đối số của làm chậm quá trình biên dịch, như cảnh báo thường có thể được tắt. Vì vậy, bất kỳ ai quan tâm về an toàn đều có thể biến chúng thành và mọi người quan tâm về tốc độ biên dịch có thể để chúng ra khỏi – user463035818

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