I have a class that has no default constructor or assignment operator so it is declared and initialized within an if/else statement depending on the result of another function. But then it says that it is out of scope later even though both routes of the conditional will create an instance.
Consider the following example (done with int just to illustrate the point):
#include <iostream>
int main()
{
if(1) {
int i = 5;
} else {
int i = 0;
}
std::cout << i << std::endl;
return 0;
}
Do variables declared in a conditional go out of scope at the end of the conditional? What is the correct way to handle the situation where there is no default constructor but the arguments for the constructor depend on certain conditionals?
Edit
In light of the answers given, the situation is more complex so maybe the approach would have to change. There is an abstract base class A and two classes B and C that derive from A. How would something like this:
if(condition) {
B obj(args);
} else {
C obj(args);
}
change the approach? Since A is abstract, I couldn't just declare A* obj and create the appropriate type with new.
"Do variables declared in a conditional go out of scope at the end of the conditional?"
Yes - the scope of a local variable only falls within enclosing brackets:
{
int x; //scope begins
//...
}//scope ends
//x is not available here
In your case, say you have class A.
If you're not dealing with pointers:
A a( condition ? 1 : 2 );
or if you're using a different constructor prototype:
A a = condition ? A(1) : A(2,3);
If you're creating the instance on the heap:
A* instance = NULL;
if ( condition )
{
instance = new A(1);
}
else
{
instance = new A(2);
}
or you could use the ternary operator:
//if condition is true, call A(1), otherwise A(2)
A* instance = new A( condition ? 1 : 2 );
EDIT:
Yes you could:
A* x = NULL; //pointer to abstract class - it works
if ( condition )
x = new B();
else
x = new C();
EDIT:
It seems what you're looking for is the factory pattern (look it up):
class A; //abstract
class B : public A;
class C : public A;
class AFactory
{
public:
A* create(int x)
{
if ( x == 0 )
return new B;
if ( x == 1 )
return new C;
return NULL;
}
};
Do variables declared in a conditional go out of scope at the end of
the conditional?
Yes.
What is the correct way to handle the situation where there is no
default constructor but the arguments for the constructor depend on
certain conditionals?
Write a function that returns a value, from which you copy.
T foo()
{
if(condition)
return T(x);
return T(y);
}
void bar()
{
T i(foo());
}
Edit:
Since A is abstract, I couldn't just declare A* obj and create the
appropriate type with new.
What do you mean? That's exactly how dynamic typing works. Except I wouldn't use a raw pointer, I would use a unique_ptr.
std::unique_ptr<A> obj;
if(condition) {
obj = std::unique_ptr<A>(new B(args));
} else {
obj = std::unique_ptr<A>(new C(args));
}
Your alternative will be pointers:
MyObject *obj;
if(cond1)
{
obj = new MyObject(1, 2, 3);
}
else
{
obj = new MyObject(4, 5);
}
Remember to delete it when you are done with it, or use a smart pointer.
Yes it will be out of scope if declared in a conditional, loop etc. Will the type of the variable change depending on the conditional?
Related
C code
#include <stdio.h>
typedef struct
{
int a;
}A;
int main()
{
A(); // this line gives error
return 0;
}
Output
Error: Expected identifier or '('
C++ code
#include <iostream>
struct A
{
int a;
A()
{
std::cout<<"Ctor-A\n";
}
~A()
{
std::cout<<"Dctor-A\n";
}
};
int main()
{
A(); // creates temporary object and destroyed it
return 0;
}
Output
Ctor-A
Dctor-A
I know about the "Rule of three", but code becomes complicated and most compilers don't give errors if we don't follow the rule. So I avoided creation of a copy constructor and an overloaded assignment operator.
Why does A()/A{} create a temporary object in C++, but not in C? What's another way to create a temporary object in C?
In C (C99 and later) you can create a structure with automatic lifetime using a Compound Literal.
The syntax is (A){ initializers, for, struct, members }.
The lifetime is automatic, not temporary, so the structure created in this way does not vanish at the end of the full-expression, but at the end of the enclosing scope.
This expression
A()
is considered by C compilers as a function call. In C++ such an expression means a call of a constructor provided that A is a class type.
To create a temporary object in C you could declare a function like for example
struct A { int a; } A( int x )
{
struct A a = { .a = x };
return a;
}
and then you can call the function creating a temporary object of the type struct A like
A( 10 );
Here is a demonstrative program.
#include <stdio.h>
struct A { int a; } A( int x )
{
struct A a = { .a = x };
return a;
}
int main(void)
{
struct A a = A( 10 );
printf( "a.a = %d\n", a.a );
return 0;
}
The program output is
a.a = 10
A() calls the constructor for the struct A in the C++ code. However, C doesn't support constructors / destructors, or even objects (in the sense of OOP) in fact. The only way to create a temporary object as you describe in C would be to declare a variable of type A and wait for it to go out of scope, where the memory allocated for it will be popped from the stack, or to allocate a variable on the heap and free it in the next line.
I have been thinking and searching this but I can't solve this question.
I would like an object that when copied into another object, both objects share certain member variable. So, when I change the value of the member variable of object1, it's also changes the variable in object2. Example:
class ABC {
public:
int a = 5;
//...
}
int main() {
ABC object1;
ABC object2 = object1;
object2.a = 7; // now, object1.a is equal to 7
object1.a = 10; // now, object2.a is equal to 10
}
I know about copy constructors, but I am not sure if it applies here or there is
a better method. I have been thinking about using pointers or references, but can't make the trick.
Note that I don't want all the objects to share the same variable.
What you need is a pointer. The pointer points to the object and then all objects that copy the first one just copy the pointer so that they all point to the same thing. To make life easy we can use a std::shared_ptr to manage the allocation and deallocation for us. Something like:
#include <memory>
class Foo
{
private:
std::shared_ptr<int> bar;
public:
Foo() : bar(std::make_shared<int>()) {}
int& getBar() { return *bar; }
};
int main()
{
Foo a;
a.getBar() = 7;
Foo b = a;
b.getBar() = 10;
// now getBar returns 10 for both a and b
Foo c;
// a and b are both 10 and c is 0 since it wasn't a copy and is it's own instance
b = c;
// now b and c are both 0 and a is still 10
}
Hi I want to call an objects function in other function but i can't. Why ?
class class1
{
private:
int var;
public:
class1(int x);
void functionO();
};
class1::class1(int x)
{
var = x;
}
void class1::functionO()
{
cout<<"text";
}
void Callfunction()
{
object1->function0();
}
int main()
{
class1 *object1;
object1 = new class1(x);
Callfunction();
}
Compilator says that
'object1' : undeclared identifier
It seems logical but how can i call that objects function within a function ?
In this code:
void Callfunction()
{
object1->function0();
}
object1 is out-of-scope. That is, the compiler doesn't know about anything named object1 from within the scope of CallFunction().
Note that even if you had defined CallFunction after main(), this would still be true. All variables are local to the scope in which they are declared.
One option is to make object1 a global, and I'm sure that you will be advised to do this. But please don't. Global variables introduce state to your program, and along with it a host of other nasty problems that are hard to fix without tearing your program apart. Don't get in to the habit of using global variables to fix all manner of scoping issues. You will regret it.
Rather, why not just pass a class1 pointer to CallFunction()? Better yet, pass a reference.
void CallFunction(class1& obj1)
{
obj1.function0();
}
int main()
{
class1 *object1;
object1 = new class1(x);
Callfunction(*object1);
}
Your problem has nothing to do with the declaration order (before or after doesn't matter). Your object1 is a local variable of main. This means that it isn't visible outside of main, unless you explicitely pass it to the function needing it or store a pointer to it in a global variable (but please don't). To solve your problem you should therefore pass your object to Callfunction:
void Callfunction(class1& object1)
{
object1.function0();
}
int main()
{
class1 object1(x);//<-- This asumes that you have actually defined x
//somewhere, otherwise replace it with an actual value
Callfunction(object1);
}
Note that I took the liberty of clearing up the unneeded indirection (and the memory leak) by constructing the object on the stack instead of on the heap.
Pass your object as (reference) parameter to your function:
class class1
{
private:
int var;
public:
class1(int x);
void function0();
};
class1::class1(int x)
: var(x) // Note: Use member initializer lists
{}
void class1::function0()
{
std::cout << "text, var = " << var << std::endl;
}
void Callfunction(class1& object)
{
object.function0();
}
int main()
{
class1 object1(10);
class1 object2(42);
Callfunction(object1);
Callfunction(object2);
}
Expected output:
text, var = 10
text, var = 42
NOTE
The declaration order also matters, you might need to use a forward declaration when class1 is declared after the compiler sees Callfunction().
I'm trying to do something like this in C++:
if(){
int a;
} else if(){
char a;
} else {
double a;
}
f(a);
But I get an error from the compiler saying that a was not declared in this scope.
I need to do a conditional declaration, how can I do it?
Many thanks
edit:
I cannot move the function inside the conditional as the problem is bigger:
f(a,b,c);
where a, b and c need to be declared in this way.
One way of doing what you seem to want is by defining a template function. You define the template and the compiler will compile versions of the function for each type you call it with.
template <typename T_my_type> T_my_type MyTemplateFunction(T_my_type a)
{
a++;
std::cout << a;
return a;
}
if(){
int a;
MyTemplateFunction(a);
} else if(){
char a;
MyTemplateFunction(a);
} else {
double a;
MyTemplateFunction(a);
}
In this case T_my_type is the template parameter and will be implicitly replaced with the type of the parameter that you call the function with.
Template programming in C++ is a rather large can of worms to open though, and as others have suggested, I think you may need to rethink your approach.
It appears that you want different overloads to be called depending on the path taken through the conditional structure. This is not possible in a static language like C++ because the compiler needs to decide which overload to call at compile time, and can only pick one for each call.
Do this instead:
if (...) {
int a = ...;
f(a);
} else if (...) {
char a = ...;
f(a);
} else {
double a = ...;
f(a);
}
C++ is a statically typed language. If you want to deal with a variable its type must be known at compile-time. If the conditions you want to check for are also known at compile-time there's probably a nice solution involving templates. If the expressions in your if statements are runtime dependent you have to move the function call inside the blocks that declare a.
you could use a union.
union my_type
{
int i;
char c;
double d;
}
my_type a;
if(){
a.i = ...;
} else if(){
a.c = ...;
} else {
a.d = ...;
}
f(a);
I don't know what f() will be doing, so I don't know if this will work in your situation. As someone else stated, templates are one option. Or you could try just type-casting instead of using a union.
Consider this instead:
union T
{
int i;
double d;
char c;
}
void process()
{
T t;
if(....) { work with t.i }
else if(....) { work with t.d }
else if(....) { work with t.c }
f(t);
}
void f(T t)
{
// now you have all your possible answers inside one variable
// you might need to send a 2nd flag to mark the actual type inside
// depending on your problem however, you might not need it
// work with t.i, t.d or t.c
}
If you must have f() on the outside and don't want to use unions, you can consider polymorphism:
class Base {};
class AInt : public Base { int a; };
class AChar : public Base { char a; };
class ADouble : public Base { double a; };
Base *p = NULL;
if(){
p = new AInt();
} else if(){
p = new AChar();
} else {
p = new ADouble();
}
f(a, b, c);
Ofcourse for this to have any real OOP quality you'll have to add some virtual methods to the Base class and implement them in the inheriting class to do the actual work you need be done or else you'll have this switch again somewhere inside f(), probing the real type of a.
You can also make f() as template function and implement the function for different data types.
f(template class T)
{
}
you can use boost library. For example
1. Boost::Any
boost::any a;
a=std::string("A string");
a=42;
a=3.1415;
f(a);
Link http://www.boost.org/doc/libs/1_40_0/doc/html/any.html
Boost::Variant
boost::variant a;
a=24;
a=2.52;
a="Fabulous!";
a=0;
f(a);
Link http://www.boost.org/doc/libs/1_40_0/doc/html/variant.html
If it possible, define macros for your conditions. In that way you can use this syntax
#if defined(CONDITION1)
int a;
f(a);
#elif defined(CONDITION2)
char a;
f(a);
#elif defined(CONDITION3)
double a;
f(a);
#endif
This is possible with a void pointer taking function. You would simply have to create a as a void* then have it point to one of your chosen variables. Then your function can simply handle which type it is. For example:
void *a;
int b;
char c;
double d;
char typeofa;
if(foo == 1){
a = &b;
typeofa = 0;
} else if(foo == 2){
a = &c;
typeofa = 1;
} else {
a = &d
typeofa = 2;
}
int bar(void* a, char typeofa)
{
//etc, do right thing dependant on typeofa
//casting a to right type then dereferencing
}
Note, I have not tested this code so it may contain minor syntax errors but demonstrates the principal.
Can a constructor call be evaluated to a boolean if the bool() operator is overloaded?
class A
{
public:
A() {};
operator bool() const { return true; }
}
main()
{
if (A a = A())
{
// do stuff
}
}
Is the above code valid, or do I need to implement main like:
int main(int argc, const char* argv[])
{
A a();
if (a)
{
// do stuff
}
}
This code is going to wind up all over the place in my code base, so less lines, increased legibility, and reduced scope are important, and would be improved by this.
Any ideas?
The code contains a few syntactic and semantic bugs. Let's fix them
class A
{
public:
A() {};
operator bool() { return true; }
};
int main()
{
if (A a = A())
{
// do stuff
}
}
You may choose to change the type in the conversion function to something else. As written, the boolean conversion will also succeed to convert to any integer type. Converting to void* will limit conversion to only bool and void*, which is a commonly used idiom. Yet another and better way is to convert to some private type, called safe bool idiom.
class A
{
private:
struct safe_bool { int true_; };
typedef int safe_bool::*safe_type;
public:
A() {};
operator safe_type() { return &safe_bool::true_; }
};
Back to syntax: If you have an else part, you may use the name of the declared variable, because it's still in scope. It's destroyed after all branches are processed successfully
if(A a = A())
{ ... }
else if(B b = a)
{ ... }
You may also use the same name as before, and the variable will shadow the other variables, but you may not declare the same name in the most outer block of any branch - it will conflict rather than hide with the other declaration.
if(int test = 0)
{ ... }
else
{ int test = 1; /* error! */ }
The technique to declare and initialize a variable is most often used together with dynamic_cast though, but can be perfectly used together with a user defined type like above, too
if(Derived *derived = dynamic_cast<Derived*>(base)) {
// do stuff
}
Note that syntactically, you have to initialize the variable (using the = expression form like for a default argument). The following is not valid
if(ifstream ifs("file.txt")) {
// invalid. Syntactic error
}
The answer to your first question is "yes", but your "constructor call" is wrong. A a declares a variable. It's a statement, not an expression. A() is an expression which constructs an anonymous temporary instance of A:
struct A
{
A() {};
operator bool() { return true; }
};
int main()
{
if (A())
{
// do stuff
}
}
If you want to use the instance of A in "stuff", then you need:
if (A a = A()) {
// do stuff
}
You can do this, but only when you're using the copy-initialization syntax to call your constructor. For example:
main()
{
if (A a = A())
{
// do stuff
}
}
Most compilers would elide the copy constructor in such an initializer when optimizations are enabled, but an accessible constructor is required nonetheless.
Also, naturally, if A would have a constructor such as A(int), you could also do this:
if (A a = 123) ...
Also, it is generally considered a bad idea to have operator bool() on your class for such purposes. The reason is that bool is in turn implicitly convertible to any numeric type (with false == 0 && true == 1); so, for example, the client of your class can write:
int x = A();
void foo(float y);
foo(A());
which is probably not something you want to allow. A simple trick is to use a pointer-to-member-of-private-class instead:
class A {
private:
struct dummy_t { int dummy; };
typedef int dummy_t::*unspecified_boolean_type;
public:
operator unspecified_boolean_type() const {
if (...) {
return &dummy_t::dummy; // true
} else {
return 0; // false
}
}
};
Pointers-to-members have an implicit bool conversion (as usual, null pointer is false, anything else is true), but they are not compatible with any type but their own; and, since the inner class here is private, no client code can possibly declare a variable of that type (auto and decltype in C++0x provide a way, though).
As a side note, main() as written is not valid C++ - ISO C++ does not have "default int" rule the way C does, and a function without an explicit return type is invalid.
If you're trying to indicate failure, why not throw an exception?
#include <stdexcept>
class Foo
{
public:
Foo(void)
{
if (/* something bad D: */)
{
throw std::runtime_error("Couldn't open file, etc...");
}
}
}
int main(void)
{
try
{
Foo f;
// do stuff with f
}
catch (std::exception& e)
{
std::cerr << "Error: " << e.what() << std::endl;
}
}