2015-06-22 16 views
13

Tôi có một lớp tiện dụng trong C++ có thể được khởi tạo hoặc với double hoặc với char*. Mọi thứ hoạt động như mong đợi ngoại trừ một trường hợp khi đối số bằng không.Zero in double vs char * ambiguity

struct Var { 
    Var (double src) {} 
    Var (char *src) {} 
}; 

int main(int argc, char* argv[]) { 
    Var A = 123; 
    Var B = "abc"; 
    Var C = 0; <- Error: conversion from 'int' to 'Var' is ambiguous 
} 

Trước đây tôi sử dụng int thay vì double, và nó là tốt đối với một số lý do.

Làm cách nào để khắc phục sự cố này?

PS: Tôi biết tôi có thể sử dụng (double)0 hoặc chỉ 0.0, nhưng là có một cách để cho phép chỉ 0 để được chấp nhận như đôi?

+6

Bạn đã thử thêm một hàm tạo chấp nhận một 'int', gọi phương thức' double'-constructor chưa? – Caramiriel

+2

Trong 'C++',' 0' có thể là số nguyên * không * hoặc * con trỏ rỗng *. Tiêu chuẩn 'C++ 11' gần đây bằng cách giới thiệu từ khóa' nullptr' cho con trỏ * null *. – Galik

+1

@Galik: Sắp xếp. Nó vẫn đúng là '0' là mơ hồ. –

Trả lời

11

Bạn có thể loại bỏ sự nhập nhằng bằng cách thêm một constructor thứ ba mà phải mất một int và các đại biểu lên phiên bản double (yêu cầu C++ 11):

struct Var { 
    Var (double src) {} 
    Var (const char *src) {} 
    // ^^^^^ should be const 
    Var (int src) : Var {static_cast<double>(src)} {} 
}; 

Tuy nhiên, điều này có thể được giải quyết dễ dàng hơn bằng cách thay đổi char* của bạn hàm tạo để thay thế std::string và sử dụng khởi tạo trực tiếp.

+0

Vâng, ai biết liệu sử dụng 'std :: string' là chấp nhận được ... Cách thay thế đầu tiên chắc chắn là tốt, nếu đó là cách nó cần được giải quyết. – Deduplicator

7

Trong C++, chữ số 0 có loại int. Bạn không thể thay đổi bất cứ điều gì về nó là một số nguyên, mà không cần thêm ít nhất một dấu thập phân. (Không cần phải thực tế để viết chữ số sau dấu mặc dù)

Để trả lời bạn câu hỏi tiềm ẩn liên quan đến lý do tại sao gọi là rõ ràng với 123 nhưng mơ hồ với 0:

  • Khi bạn khởi tạo A, nó là tốt vì không có chuyển đổi ngầm từ một int đến một con trỏ (char*, trong trường hợp này).

  • Khi bạn khởi tạo C sử dụng một int lần thứ hai, bạn sử dụng 0, các literal 0 có thể được ngầm chuyển đổi sang một con trỏ (một số hành vi di sản, trước khi C++ 11 cung cấp nullptr đen).

Vì vậy, trong một nutshell:

int * a = 0; // legal; 
int * b = 2; // ILLEGAL; 

Khi khởi C một chuyển đổi là cần thiết để cung cấp cho các lập luận để bất kỳ của hai nhà xây dựng sẵn (và cả hai chuyển đổi có bảng xếp hạng tương tự), cuộc gọi là mơ hồ.

Để làm cho nó rõ ràng, bạn nên đúc chữ cái của bạn thành chữ gấp đôi ((double)0), sử dụng chữ kép (0.) hoặc thêm một hàm tạo tham số. Với giải pháp cuối cùng này, hàm tạo tham gia int là kết hợp chính xác, do đó, kết hợp tốt hơn là quá tải khác cần chuyển đổi (đó là lý do tại sao nó được chọn).

Chỉnh sửa. Xin lưu ý rằng Câu trả lời TartanLlama phải được chấp nhận ở đây vì đây là thực hành C++ tốt nhất: hàm tạo sử dụng chuỗi kiểu C phải thay thế std::string.Kể từ khi có một chuyển đổi ngầm từ chuỗi C-style để std::string, cuộc gọi sẽ làm việc với sự thay đổi nhỏ:

Var B("abc"); 

Nhưng bạn sẽ cô lập giao diện lớp học của bạn từ gợi ý chi tiết.

+2

Re "Chữ số 0 có kiểu int". Điều gì về con trỏ null? Và các chức năng ảo thuần túy? –

+2

@PeterMortensen: Con trỏ rỗng liên quan đến chuyển đổi, do đó, nó được xếp hạng kém hơn trong quá trình phân giải quá tải so với kết hợp trực tiếp với 'int'. Các hàm ảo thuần túy không liên quan gì đến chữ '0', ngữ pháp không chấp nhận một chữ ở đó, chỉ có chuỗi ký tự' = 0'. (Ví dụ, '0x0' cũng là một số nguyên bằng không, và cũng có thể chuyển đổi thành một con trỏ rỗng, nhưng không thể chấp nhận được trong một bộ định danh thuần) –