Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I'm pretty new to c++ language however I have experience with python and a little bit with java.
Since c++ is pretty overwhelming and there is like always few ways to achieve certain behavior I have 2 questions related to oop.
What is the best way to create class constructor with parameters?
For example let's say we have sth like that:
struct Test {
int x;
int y;
};
And there are 2 popular ways for constructor:
1.
Test(int x, int y) : x{x}, y{y} { // rest of constructor};
Test(int x1, int y1) {
x = x1;
y = y1;
// rest of constructor
}
Which one should I use and why?
Which style is more like c++ to create class object and why?
Test* testptr = new Test(1, 1);
vs
Test test = Test(1, 1);
The most C++-ish way to create a struct is struct_name{value1, value2}. And you don't need to declare your own constructor.
If you really want to use a constructor, use the one with initializer syntax. Here is the difference. Let's consider a structure with two fields. So it looks like: {one, two}. When you use initializer syntax, you create the needed struct immediately before the actual constructor code you wrote between curly braces. So it looks like: {1, 2} (we have values now). However, when you initialize those fields inside a constructor's body, it will create a structure with default values first and then change them. So it looks like: {0, 0} ...constructor is working... {1,2}.
Ok, the last thing about it is parameter declaration. You should use constant references as it prevents a programmer from changing those parameters inside the function body, and these variables are passed by reference and not copied. Let's look at two examples:
void fun1(int a, int b);
void fun2(const int& a, const int& b);
fun1 here copies those two parameters before using them inside the body. However, fun2 gets only references to the variables and work with their values directly. Also, because of the const, you cannot change them, so it is completely safe.
Modern C++ does not like the new operator. We use it only inside constructors and calling the delete operator in destructors. However, it is not recommended to use the new operator in other cases as it is much harder to prevent memory leaks, and it violates the RAII idiom. If you really must use raw pointers, then consider putting them inside smart pointers.
Related
This question already has answers here:
Is there a difference between copy initialization and direct initialization?
(9 answers)
Closed 2 years ago.
I have noticed that both int num(5) and int num = 5 both compile and assign 5 to num.
Questions
Could you help me understand why int num(5) work? This syntax looks like initializing an object
What is the difference between the two in terms of speed and stuff that goes behind
Pardon me if it's a silly question. I am a noob at C++ and in process to learn stuff.
Could you help me understand why int num(5) work? This syntax looks
like initializing an object
For the basic case (where the programmer explicitly types in a line of code like int num(5); or int num = 5;, having two different syntaxes that both do the same thing seems unnecessary, and it is.
However, once you get into templates, you'll find cases where you want to write a template that can work with both user-defined classes and with the built-in types. For example, here is a template I wrote the other day to save (and later restore) the state of an arbitrary value:
template<class T> class SaveGuard
{
public:
SaveGuard(T & saveMe) : _saveMe(saveMe), _tempHolder(saveMe) {/* empty */} // save the current value
~SaveGuard() {_saveMe = _tempHolder;} // restore the saved value
private:
T & _saveMe;
T _tempHolder;
};
Note that in this case, the _tempHolder(saveMe) clause is syntactically the same as the int(5) syntax, and since the int(5) syntax is supported, I can declare a SaveGuard<int> guard(blah); in my program and it will work as expected. Alternatively I can declare a SaveGuard<MyClassType> guard(blah); and the template will work for that as well, using the copy-constructor of the MyClassType class.
What is the difference between the two in terms of speed and stuff
that goes behind
There's no difference in speed in your example; the compiler will generate the same assembly code for either syntax.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I'm trying to do a bit of refactoring and I am curious about how would you approach this problem.
Basically I'm trying to create an initialization function for each class. There are classes that inherit from some others, and i would like to use parent initialization function if possible. How would you address this?
I would like to use these structs with memcpy and maybe using also them with the keywords align and __attribute__((packed)); and they must be usable with extern "C". I would exclude then constructors and destructors.
An example to explain:
struct A
{
int a;
};
void initialize(A& a)
{
a = 0;
}
struct B : A
{
int b;
};
void initialize(B& b)
{
initialize(b); // here I want void initialize(A& a), not recursion
b = 0;
};
Maybe I have to do some kind of cast? Ideally I'm looking a solution that does not create overhead.
Use a static_cast.
In your code, the initialize(b) call will recurse infinitely, because b is better matched as B& than as A& (the argument of the function you want to call), thus the overload resolution picks the same function and recurs.
You specified that you want to initialise the A part of the b object. Why not tell that to the compiler? Tell it that you want to call initialise in it as though it was an A, like so:
initialize(static_cast<A&>(b));
As for your concern that you mentioned in the comment - no copies are being made here. If I used static_cast<A>, however, a temporary object would be created, but that's not the case. I am not casting b to an object of a type A. I am casting it to a reference of a type A, which will result in creation of temporary reference. Since A& matches with A& better than with B&, the first function will be chosen, thus avoiding the recursion.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I know how useful it is to declare variable as a reference or pointer in a function, but I just wonder why we declare it as a reference in the private section of a class.
example
class DoSomething
{
private : int& t_; // why not just 'int t;'
};
How about if we declare the variable without reference, and define the object of a class as a pointer or reference? Is this not good practice?
If you declare the variable as int, its value would be "divorced" from the variable from which it has been initialized. If you keep it a reference, the variable would be "tracking" the variable with which it has been initialized:
class demoRef {
int &r;
public:
demoRef(int& x) : r(x) {}
void show() {cout << r << endl;}
};
class demoCopy {
int r;
public:
demoCopy(int& x) : r(x) {}
void show() {cout << r << endl;}
};
int main() {
int x = 123;
demoRef dRef(x);
demoCopy dCopy(x);
dRef.show();
dCopy.show();
x = 456;
dRef.show();
dCopy.show();
return 0;
}
This code produces the output below:
123
123
456
123
Demo on ideone.
Note: this is only an illustration of what you can do with a reference to an int. It is not meant to imply that you should do something like this without being extra careful, because a hidden reference like this makes your code harder to read.
There are many reasons you might have a reference member. An example from the standard library is the back_insert_iterator, which keeps a reference (or a pointer) to a container in order to call that container's push_back function.
Note that with any class like this, which stores a reference or pointer to another object, you need to take the same care as you would with a raw reference or pointer. That is, you need to be wary of dangling references, and ensure that you don't use the reference past the lifetime of the referent.
When you store a reference to a variable in a class, the outcome of changing the variable is:
You can change the variable in a member function of DoSomething and have that change be visible outside the class.
You can change the variable outside DoSomething and have that change be visible inside DoSomething.
The key question is: Where is it useful?
I have often found it useful in a functor that is passed to some of the functions in the standard library.
#BenjaminLindley already gave you a very good example of that.
I have often found it useful in Factory Patterns when a concrete Product is created using the data stored in a concrete Factory but the data is too expensive to copy.
I have used it in classes that implement a functional interface. These classes hold references to other data when:
3.1. The class needs to access to the data but it is too expensive to copy the data.
3.2. It makes no sense to copy the data or copying is prohibited by design (such as std::ofstream).
3.3. The class needs to update the data and make it visible to the calling code.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
Since C++11 we can default construct our variables in a class, like this:
class Foo{
private:
int bar = 0;
};
I've very rarely seen someone using this feature
Is this a good practice ?
This is a style question, but there are some considerations that are hopefully universal:
If all constructors of your class have to initialize a member the same way, because the initial value is in some profound way part of the invariants of the class, then it is both more readable and self-documenting and also shorter to use the inline initializer, and the deduplication removes a source of errors if you ever need to change the initial value.
Otherwise, if different constructors supply different initial values, then you shouldn't have an inline initializer, even though that's technically permitted.
I dont see any bad practices in this approach. This is allowed even in Higher level languages like Java. It reduces lines of code inside constructor.
The only big disadvantage I see is that it may lead people to expose more implementation details than necessary in class definitions. Currently, if you initialize a member in MyClass.cpp, then you can easily change the value later on. If you initialize the member in MyClass.h, then a lot of recompilation could be necessary if you later change the value.
In Java, you don't have this kind of separation between header and implementation, so the situation cannot be compared to C++.
C++11 allows non-static data members to be initialized in-class.
This can often save some typing. Consider the following example:
class Foo {
public:
Foo() : a_{5}, b_{7}, s_{"Foo"}, bar_{"Test"} {}
Foo(int x) : a_{x}, b_{7}, s_{"Foo"}, bar_{"Test"} {}
Foo(double d) : a_{5}, b_{g(d)}, s_{"Foo"}, bar_{"Test"} {}
int someFunc();
private:
int a_;
int b_;
std::string s_;
Bar bar_;
};
Using in-class initialization will IMHO make the code more readable.
class Foo {
public:
Foo() = default;
Foo(int x) : a_{x} {} // Initialization list overrides in-class initialization.
Foo(double d) : b_{g(d)} {} // Same here.
int someFunc();
private:
int a_ = 5;
int b_ = 7;
std::string s_{"Foo"};
Bar bar_{"Test"};
};
I would say use it when possible. An exception is when the situation described in this answer applies.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
class test {
public:
test(int value = 0): x(value) {}
int& get(){
return x;
}
private:
int x;
};
this will allow client code to mutate the private members
this is legal in C++, but why ?
Is there any situation where you would actually need to break the class encapsulation ?
Make a member as private, means you can not access it directly. But nothing restricts you to access it indirectly via a public member. It depends on you design. You can even do this:
class test {
public:
test() : x(y) {}
int &x;
private:
int y;
};
In your class, assume you want count how many times a member is read/write. So, you can make it private then put a member function which returns a refernce to the variable:
class test {
public:
test(int value = 0): x(value), count(0) {}
int& get(){
count++;
return x;
}
private:
int x;
int count;
};
I hope this example shows how making a member as private and then putting an indirect access to it can be useful.
Ffirst of all let's consider implementing what you describe. It would be very onerous to properly do so. Your example is easy enough. But what if the reference flowed through a number of functions before it reached the function that exposed it? The compiler would have to do exceptionally complex static analysis, beyond the levels of static analysis that are reasonable to expect from compiler writers.
So even if the designers wanted to ban this, it would not have been tractable to do so. Would the designers have wanted to stop this? Very doubtful. Had they done so, how would the [] operator be implemented on a container or a string?
Is there any situation where you would actually need to
break the class encapsulation
As example of the [] operator on containers and strings shows, this feature is in fact used to support encapsulation.
Why? Because C++ mainly tries to let you do whatever you want and not get in your way; it doesn't try very hard to keep you safe. If you want a safe language, use something else. You have something like object-orientation if you want to, but if you want to break out of that, more power to you. With great power comes great responsibility.
It's worth nothing that you don't even need this to break encapsulation; you could simply reinterpret a pointer to "test" as an integer and access the private field this way.