Предположим, у меня есть класс:
class foo
{
....
//some constructors here set val=34
....
private:
int val;
int & foo::operator,()
{
return val;
}
};
и я хочу иметь возможность использовать его как:
foo bar;
printf(" %d ", bar); //i need to get value of bar.val
//with just using bar itself with
//using an overloading
//but , overloading does not work
//i need to get 34 without using bar.val
//i need this without any getter
//i need val to be private
Вопрос: возможна ли такая перегрузка? Если да, то как?
Я старался:
int foo::operator int()
{
return val;
}
но он говорит «тип возврата не может быть конкретным для функции преобразования» 🙁
Я старался:
operator int() const { return val; }
преобразование работает только за пределами printf & соиЬ.
int e=foo;
printf(" %d ",e); //works
Вы не можете перегружать класс, но вы можете использовать оператор преобразования, чтобы он автоматически конвертировал в различные типы в соответствии с ожидаемыми параметрами в этом контексте. В вашем случае, как val
является int
, вы бы перегружали конвертацию в int
как это:
operator int() const { return val; }
Теперь везде, где int
требуется, и вы предоставляете foo
, это преобразование применяется.
Есть некоторые ограничения. Например, если вы передаете foo
в шаблон функции, где тип соответствующего аргумента является общим, в этом месте преобразование не будет. Преобразование также не повлияет на другие выражения, которые не поддерживают тип. В качестве примера, если f
это тип foo
, затем &f
всегда будет иметь тип foo*
не int*
, Для большинства практических применений все это именно то, что вам нужно. Но я считаю, что C-стиль Variadic printf
это как раз тот случай, когда нет четко определенного ожидаемого типа. Лучше использовать вызов в стиле C ++ или явное приведение static_cast<int>(f)
,
Если ни то, ни другое не приемлемо для вас, то вы попадаете в беду: логика C ++ не может сделать вывод, что вам требуется int
здесь, просто потому что вы включили %d
в некоторых строковых константах. Преобразование типов выполняется во время компиляции, тогда как интерпретация строк формата выполняется во время выполнения (кроме случаев, когда генерируются предупреждения, как, например, делает gcc). Компилятор не будет знать, какого типа должен быть этот аргумент, поэтому он не будет знать, какое преобразование выполнить, поэтому вы должны каким-то образом ему помочь.
Пока это int val
является единственным членом foo
и в этом классе нет виртуальных функций, и там нет базового класса с какими-либо членами данных или виртуальной функции, структуры памяти объекта класса foo
обычно будет таким же, как и у простого целого числа. Это означает, что нетипизированный стиль C printf
не сможет заметить разницу, даже без какого-либо преобразования вообще. Но полагаться на это действительно плохой стиль, поэтому я бы посоветовал не использовать это.
Не перегружайте запятыми или чем-то таким ужасным. printf
имеет параметр многоточия, поэтому он принимает все, что вы подаете на него, вы должны убедиться, что то, что вы предоставляете, является правильным. Будь проще:
class foo
{
....
//some constructors here set val=34
....
private:
int val;
public:
int value()
{
return val;
}
};
int main()
{
foo bar;
printf(" %d ", bar.value()); //you get value of bar.val
}
printf
не вызывает никаких операторов на вашей панели (включая операторов преобразования), поэтому они вам не помогут. Даже если бы вы имели operator int()
вы все равно должны написать это так:
printf(" %d ", (int)bar); //you get value of bar.val
Это не намного лучше выглядит. Или даже:
printf(" %d ", +bar); //you get value of bar.val
Самое запутанное.
Нет, это невозможно.
Во-первых, оператор запятой здесь не применяется, потому что запятая используется для разделения аргументов printf, которая имеет приоритет над запятой, используемой в качестве оператора.
Добавление оператора преобразования не помогает, потому что объявление printf
printf(const char *,...);
Это означает, что компилятор не знает, каким должен быть тип параметров (кроме первого), поэтому он не будет выполнять никакого преобразования.