OOP - abstract class types, intializing variables in base and derived classes - c++

Similar to: How can I initialize base class member variables in derived class constructor?, but I was wondering why if I have:
class A {
public:
A(int val);
virtual int get_val() = 0;
protected:
int val;
};
class B : public A {
public:
B(int val, int extra);
int get_val() = 0;
private:
int extra;
};
I'm wondering what is the difference between doing this:
A::A(int val) : val(val) {}
and:
A::A(int val) {val = val;}
And also why, when I'm in the constructor for class B, I can't do:
B::B(int b, int extra) : A(b) {
extra = extra;
}
But I can do:
B::B(int b, int extra) : A(b) {
this->extra = extra;
}
or,
B::B(int b, int extra) : A(b), extra(extra){}
to store the value of extra in B. If I don't do those it's not stored. I'm very confused what's happening.

I'm wondering what is the difference between doing this:
A::A(int val) : val(val) {}
and:
A::A(int val) {val = val;}
The first is right and the second is wrong.
More precisely, the first one initialises the data member A::val with the value of the constructor parameter val, which is without any doubt precisely what you intend to do.
The second one, in contrast, does nothing with A::val, leaving it with an uninitialised value, which will later cause undefined behaviour as soon as you try to read from the data member. The val = val; line assigns the constructor parameter val to itself, which is completely meaningless.
The second one would be okayish if you used a different parameter name to disambiguate, for example:
A::A(int new_val) { val = new_val; }
It would also work fine if you did like in your own this->extra = extra; example:
A::A(int val) { this->val = val; }
In both cases, the compiler now knows that you mean A::val.
However, this form of constructor implementation is atypical in C++ and often a sign of a Java or C# programmer. It leaves A::val uninitialised for a moment and then assigns it a value. That just isn't very logical. Why not initialise it right away if you can? It also won't work with const members, with reference members or with data types that don't have default constructors or a way to assign something later.
By the way, this doesn't have anything to do with efficiency but only with correctness and readability.

I'm wondering what is the difference between doing this:
A::A(int val) : val(val) {}
and:
A::A(int val) {val = val;}
No difference for primitive types. However, if val is a non-primitive type, e.g. std::string, Using the first way(initialization list) is more efficient. Think of
Method 1 is the same as:
string val(val);
Method 2 is the same as:
string val; //default initialize first;
val = val2; //assign val2 to val
That is, even if you do not provide anything in the initialization list, compiler will still call the default constructor to initialize it first before going into {} block. Since primitive types do not have constructors, using initialization list does not really improve the efficiency.
And also why, when I'm in the constructor for class B, I can't do:
B::B(int b, int extra) : A(b) {
extra = extra;
}
Similar to the explanation above. Inside the {}, "extra" will be defined, and local object overshadow the data member. However, there is no harm in choosing a different parameter name.

Related

Using new (this) to reuse constructors

This came up recently in a class for which I am a teaching assistant. We were teaching the students how to do copy constructors in c++, and the students who were originally taught java asked if you can call one constructor from another. I know the answer to this is no, as they are using the pedantic flag for their code in class, and the old standards do not have support for this. I found on Stackoverflow and other sites a suggestion to fake this using new (this) such as follows
class MyClass
{
private:
int * storedValue;
public:
MyClass(int initialValue = 0)
{
storedValue = new int(initialValue);
}
~ MyClass()
{
delete storedValue;
}
MyClass(const MyClass &b)
{
new (this) MyClass(*(b.storedValue));
}
int value() {
return *storedValue;
}
};
This is really simple code, and obviously does not save any code by reusing the constructor, but it is just for example.
My question is if this is even standard compliant, and if there are any edge cases that should be considered that would prevent this from being sound code?
Edit: I should note that this seems very dangerous to me, but that is more from a view point of I don't really understand it more than knowing how it can go bad. I just wanted to make sure that if asked about it by students that I can direct them towards why the can or shouldn't do it. I already suggested to them for all practical purposes to use a shared initialization method. This is more of a teaching question than for a practical project.
C++0x will introduce syntax to allow constructors to call other constructors.
Until then, new(this) works in some cases, but not all. In particular, once in the constructor, your base class(es) are already fully constructed. Reconstructing via new(this) re-calls the base constructors without calling the base destructors, so expect problems if the base classes weren't expecting this kind of hackery - and they probably weren't.
An example for clarity:
class Base
{
public:
char *ptr;
MyFile file;
std::vector vect;
Base()
{
ptr = new char[1000];
file.open("some_file");
}
~Base()
{
delete [] ptr;
file.close();
}
};
class Derived : Base
{
Derived(Foo foo)
{
}
Derived(Bar bar)
{
printf(ptr...); // ptr in base is already valid
new (this) Derived(bar.foo); // ptr re-allocated, original not deleted
//Base.file opened twice, not closed
// vect is who-knows-what
// etc
}
}
or as they say 'hilarity ensues'
The members and base classes will be initialised before entering the constructor body, then initialised again when you call the second constructor. In general this will lead to memory leaks and possibly undefined behaviour.
So the answer is "no, this is not sound code".
Here is what C++ FAQ has to say about it, in the question, β€œCan one constructor of a class call another constructor of the same class to initialize the this object?”:
BTW do NOT try to achieve this via placement new. Some people think they can say new(this) Foo(x, int(x)+7) within the body of Foo::Foo(char). However that is bad, bad, bad. Please don't write me and tell me that it seems to work on your particular version of your particular compiler; it's bad. Constructors do a bunch of little magical things behind the scenes, but that bad technique steps on those partially constructed bits. Just say no.
Unless you're trying to call a parent's constructor, I'd suggest making a private initialization method. There's no reason you couldn't call a shared initializer across your constructors.
This does not work if you have a constructor like that:
class MyClass {
public:
MyClass( const std::string & PathToFile )
: m_File( PathToFile.c_str( ) )
{
}
private:
std::ifstream m_File;
}
The original argument cannot be recovered, so you cannot call that constructor from a copy-constructor.
As that exact code is written, it should work -- though I can't imagine exactly why you'd write code like that. In particular, it depends on the fact that all the pointer is only ever used to refer to a single int. That being the case, why didn't they just put an int in the object, instead of using a pointer and allocating the int dynamically? In short, what they have is long and inefficient, but not significantly different from:
class MyClass {
int v;
public:
MyClass(int init) : v(init) {}
int value() { return v; }
};
Unfortunately, the minute you try to get some real use from the pointer (e.g., allocating different amounts of memory in different objects) the "trick" they using with placement new quits working -- it depends completely on the fact that every object is allocating exactly the same amount of memory. Since you're limited to exactly the same allocation in each, why put that allocation in the heap instead of making it part of the object itself?
Truthfully, there are circumstances when it would make sense. The only one I can think of right off, however, is that the allocation is large and you're running in an environment where there's a lot more heap space than stack space.
The code works, but it's only useful under fairly narrow, specific circumstances. It doesn't strike me as something I'd recommend as an example of how to do things.
It seems to me that it's possible to use new(this) safely even in the constructor of a derived class, if you know what you're doing. You just have to make sure that your base class has a dummy constructor (and the same for its base class, all the way down the chain). For example:
#include <stdio.h>
#include <new>
struct Dummy {};
struct print
{
print(const char *message) { fputs(message, stdout); }
print(const char *format, int arg1) { printf(format, arg1); }
print(const char *format, int arg1, int arg2) { printf(format, arg1, arg2); }
};
struct print2 : public print
{
print2(const char *message) : print(message) {}
print2(const char *format, int arg1) : print(format, arg1) {}
print2(const char *format, int arg1, int arg2) : print(format, arg1, arg2) {}
};
class foo : public print
{
int *n;
public:
foo(Dummy) : print("foo::foo(Dummy) {}\n") {}
foo() : print("foo::foo() : n(new int) {}\n"), n(new int) {}
foo(int n) : print("foo::foo(int n=%d) : n(new int(n)) {}\n", n), n(new int(n)) {}
int Get() const { return *n; }
~foo()
{
printf("foo::~foo() { delete n; }\n");
delete n;
}
};
class bar : public print2, public foo
{
public:
bar(int x, int y) : print2("bar::bar(int x=%d, int y=%d) : foo(x*y) {}\n", x, y), foo(x*y) {}
bar(int n) : print2("bar::bar(int n=%d) : foo(Dummy()) { new(this) bar(n, n); }\n", n), foo(Dummy())
{
__assume(this); // without this, MSVC++ compiles two extra instructions checking if this==NULL and skipping the constructor call if it does
new(this) bar(n, n);
}
~bar()
{
printf("bar::~bar() {}\n");
}
};
void main()
{
printf("bar z(4);\n");
bar z(4);
printf("z.Get() == %d\n", z.Get());
}
Output:
bar z(4);
bar::bar(int n=4) : foo(Dummy()) { new(this) bar(n, n); }
foo::foo(Dummy) {}
bar::bar(int x=4, int y=4) : foo(x*y) {}
foo::foo(int n=16) : n(new int(n)) {}
z.Get() == 16
bar::~bar() {}
foo::~foo() { delete n; }
Of course you're out of luck if the base class has constant* or reference members (or if you can't edit the file containing the base class's declaration). That would make it impossible to write a dummy constructor in it β€” not to mention that with "new(this)", you'd then be initializing these "constant" members twice! That's where the real thing, C++0x delegating constructors, could really come in handy.
Please tell me if there's anything else about this technique that can still be unsafe or non-portable.
(Edit: I've also realized that maybe in a virtual class, the virtual function table might be initialized twice. That would be harmless, but inefficient. I need to try that and see what the compiled code looks like.)
*If you merely have constant members (and no references) in the base class, you're not completely out of luck. You can just make sure all the classes of all the constant members have their own dummy constructors that the base class's dummy constructor can call in turn. You're out of luck if some of the constants have built-in types like int, though β€” those will be initialized unavoidably (e.g., a const int will be initialized to zero).
Edit: Here's an example of chaining dummy constructors, that would be broken if int value became const int value inside class FooBar:
#include <stdio.h>
#include <new>
struct Dummy {};
struct print
{
print(const char *message) { fputs(message, stdout); }
print(const char *format, int arg1) { printf(format, arg1); }
print(const char *format, int arg1, int arg2) { printf(format, arg1, arg2); }
};
struct print2 : public print
{
print2(const char *message) : print(message) {}
print2(const char *format, int arg1) : print(format, arg1) {}
print2(const char *format, int arg1, int arg2) : print(format, arg1, arg2) {}
};
class FooBar : public print
{
int value;
public:
FooBar() : print("FooBar::FooBar() : value(0x12345678) {}\n"), value(0x12345678) {}
FooBar(Dummy) : print("FooBar::FooBar(Dummy) {}\n") {}
int Get() const { return value; }
};
class foo : public print
{
const FooBar j;
int *n;
public:
foo(Dummy) : print("foo::foo(Dummy) : j(Dummy) {}\n"), j(Dummy()) {}
foo() : print("foo::foo() : n(new int), j() {}\n"), n(new int), j() {}
foo(int n) : print("foo::foo(int n=%d) : n(new int(n)), j() {}\n", n), n(new int(n)), j() {}
int Get() const { return *n; }
int GetJ() const { return j.Get(); }
~foo()
{
printf("foo::~foo() { delete n; }\n");
delete n;
}
};
class bar : public print2, public foo
{
public:
bar(int x, int y) : print2("bar::bar(int x=%d, int y=%d) : foo(x*y) {}\n", x, y), foo(x*y) {}
bar(int n) : print2("bar::bar(int n=%d) : foo(Dummy()) { new(this) bar(n, n); }\n", n), foo(Dummy())
{
printf("GetJ() == 0x%X\n", GetJ());
__assume(this); // without this, MSVC++ compiles two extra instructions checking if this==NULL and skipping the constructor call if it does
new(this) bar(n, n);
}
~bar()
{
printf("bar::~bar() {}\n");
}
};
void main()
{
printf("bar z(4);\n");
bar z(4);
printf("z.Get() == %d\n", z.Get());
printf("z.GetJ() == 0x%X\n", z.GetJ());
}
Output:
bar z(4);
bar::bar(int n=4) : foo(Dummy()) { new(this) bar(n, n); }
foo::foo(Dummy) : j(Dummy) {}
FooBar::FooBar(Dummy) {}
GetJ() == 0xCCCCCCCC
bar::bar(int x=4, int y=4) : foo(x*y) {}
foo::foo(int n=16) : n(new int(n)), j() {}
FooBar::FooBar() : value(0x12345678) {}
z.Get() == 16
z.GetJ() == 0x12345678
bar::~bar() {}
foo::~foo() { delete n; }
(The 0xCCCCCCCC is what uninitialized memory is initalized with in the Debug build.)

Intermediate calculations inside initialization list

I have something like
struct Foo {
const double a;
const double b;
Foo(double c);
}
Foo::Foo(double c) {
double tmp = f(c);
a = g(tmp);
b = h(tmp);
}
where f,g,h are functions implemented elsewhere. This gives the expected "uninitialized const member" error.
I could fix it with
Foo::Foo(double c): a (g(f(c))), b (h(f(c))) {}
but f is an expensive function and I wouldn't like to run it twice.
My question is, how can I solve this problem without running f twice or making tmp a permanent member of Foo?
Typically, delegating constructors offer a simple solution to this type of problem. In this case you'll have to introduce some way to distinguish between the two constructors:
private:
// the int param is unused
Foo(double fc, int) : a(g(fc)), b(h(fc)) {}
public:
Foo(double c) : Foo(f(c), 0) {}

C++ private member variables same name as ctor params

I know that many peoplpe use a prefix or suffix for private member variable names. For those who don't, but just use the name - how do you initialize them if you want to have constructor params of the same name?
By simply writing them. The rules of the language prevent problems.
struct Foo
{
Foo(int x) : x(x) {};
int x;
};
Outside the (), only the data member is in scope; inside, the function argument hides the member just as it would in a normal function body:
int x = 2;
void foo(int x)
{
// any access to `x` means the argument
}
This is one of many reasons that I do not use the m_ prefix style (or equivalent) when naming data members.
You just initialize them in the initialization list:
struct foo
{
foo(int bar) : bar(bar) {}
private:
int bar;
};
Note that the initialization list is the only way to explicitly initialize a member in a constructor. Once you're in the body of the constructor, the member has already been initialized.
As an aside, C++ allows you to initialize a member at the point of declaration, in which case it is initialized to that value unless otherwise initialized in the constructor:
struct foo
{
foo(int bar) : bar(bar) {}
foo() {} // bar initialized to 42
private:
int bar = 42;
};
If you use an initializer list, you can simply use the same name and the compiler will understand what you mean.
Example:
Book::Book(std::string title, int year)
: title(title), year(year)
{}
The simplest way is to use a mem-initializer list. For example
class A
{
private:
int data;
public:
A( int data ) : data( data ) {}
};
If you want to use the data member within the constructor's body then there are two approaches to distinguish the data member and the parameter
class A
{
private:
int data;
public:
A( int data ) : data( data )
{
A::data *= data;
this->data *= data;
}
};
The method formal name is not of high value, considering how limited it's scope is. And yet there should still be motivation to be able to instantly distinguish these items 'origins' at a glance.
It has become my practice to both
a) prefix my data attribute names with 'm_',
AND
b) prefix the method / function parameter names with 'a_' or 'an_', always striving for grammatical correctness.
LMBM::Node::Node(uint8_t a_max) : m_max (a_max) ...
void* LMBM::Node::threadEntry(void* an_objPtr) ...
void DV1::processDirent(const std::string& a_dirPath) ...
void DV1::handleDT_REG (DV::Dirent* an_ent,
const std::string& a_path) ...
FInfo (const std::string& aPfn, const int64_t& aFileSz) :
m_pfn (aPfn),
m_fileSz (aFileSz) ...
Goal - easier to read
Motivation - code is written once, read many times
I understand the special case for the ctor initializer list. But I am also confident that the use of prefixes (of your choice) do help prevent several kinds of mistakes that occur during development and maintenance.

Multi argument for implicit conversion

For a constructor with multiple arguments...
For example:
class C {
public:
C(int a=1, int b=2){ cout << a << ", " << b << "\n"; }
}
int main(){
C a(10), b = 20;
}
output:
10, 2
20, 2
How do I just assign value to the 2nd parameter? So that I can get "1, 20" without knowing the default values? Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
And how do I implicitly assign all the parameters? If I can't do that, why? For the above example (as I am new to C++), I once thought I would get "10, 20" as output instead.
Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
Yes. Otherwise, how is the compiler supposed to know which argument should be used for which parameter?
However, there are ways to accomplish this. For example,
struct C {
enum { DefaultA = 1, DefaultB = 2 };
C(int a = DefaultA, int b = DefaultB) { /* ... */ }
};
C object(C::DefaultA, 20);
Or, if you have a lot of parameters with different "defaults:"
struct CParams {
int a, b;
CParams() : a(1), b(2) { }
};
struct C {
C(CParams x) { /* ... */ }
};
CParams params;
params.b = 20;
C object(params);
C++ doesn't support named arguments. You have to specify the first one.
Also, the variable name b from the main function is completely separate from the b in the constructor definition. There's no relationship whatsoever implied by the naming.
I had the same thought (Convienient C++ struct initialisation -- perhaps you find something you like better there) some time ago, but just now, reading your question, I thought of a way to actually accomplish this. But it is quite some extra code, so the question remains if it is actually worth it. I just implemented it very sketchy and I am not proud of my choice of names (I usually don't use _ but it's late). Anyway, this is how you can do it:
#include <iostream>
struct C_members {
int a;
int b;
C_members(int _a, int _b) : a(_a), b(_b) {}
};
class C_init {
public:
virtual C_members get(C_members init) const {
return init;
}
};
class C_a : public C_init {
private:
int a;
public:
C_a(int _a) : a(_a) {}
C_members get(C_members init) const {
init.a = a;
return init;
}
};
class C_b : public C_init {
private:
int b;
public:
C_b(int _b) : b(_b) {}
C_members get(C_members init) const {
init.b = b;
return init;
}
};
class C : private C_members {
private:
static const C_members def;
public:
C(C_init const& ai = C_init(), C_init const& bi = C_init()) : C_members(ai.get(bi.get(def)).a, bi.get(ai.get(def)).b) {
std::cout << a << "," << b << std::endl;
}
};
const C_members C::def(1,2); // default values
// usage:
int main() {
C c1(C_b(77)); // 1,77
C c2(C_a(12)); // 12,2
C c3(C_b(5),C_a(6)); // 6,5
return 0;
}
There is a lot of stuff that can be improved (with templates (for code reduction) and with const refs in the get method), but you get the idea.
As a bonus feature, you almost have the pimpl idiom implemented (very little effort is necessary to extend this to an actual pimpl design).
Usually in OOP, every object instance holds (and represents) a state.
So the best way is to define an accessor functions such as
void setB(int newBvalue);
and also to hold b as a private member.
if "b" is shared among all the instances of the same object, consider to save a static variable.

Initialising reference in constructor C++

I don't think is a duplicate question. There are similar ones but they're not helping me solve my problem.
According to this, the following is valid in C++:
class c {
public:
int& i;
};
However, when I do this, I get the following error:
error: uninitialized reference member 'c::i'
How can I initialise successfully do i=0on construction?
Many thanks.
There is no such thing as an "empty reference". You have to provide a reference at object initialization. Put it in the constructor's base initializer list:
class c
{
public:
c(int & a) : i(a) { }
int & i;
};
An alternative would be i(*new int), but that'd be terrible.
Edit: To maybe answer your question, you probably just want i to be a member object, not a reference, so just say int i;, and write the constructor either as c() : i(0) {} or as c(int a = 0) : i(a) { }.
A reference must be initialised to
refer to something.
int a;
class c {
public:
int& i;
c() : i (a) {};
};
Apart from the sweet syntax, a key feature of references is that you are pretty sure that it always point to a value (No NULL value).
When designing an API, it forces user to not send you NULL.
When consuming an API, you know without reading the doc that NULL is not an option here.
References have to be initialized upon creation. Thus you have to initialize it when the class is created. Also you have to provide some legal object to reference.
You have to use the initializer in your constructor:
class c {
public:
c(const int& other) : i(other) {}
int& i;
};
Reference should be initialised either by passing data to constructor or allocate memory from heap if you want to initialize in default constructor.
class Test
{
private:
int& val;
std::set<int>& _set;
public:
Test() : val (*(new int())),
_set(*(new std::set<int>())) { }
Test(int &a, std::set<int>& sett) : val(a), _set(sett) { }
};
int main()
{
cout << "Hello World!" << endl;
Test obj;
int a; std::set<int> sett;
Test obj1(a, sett);
return 0;
}
Thanks
template<class T>
class AVLNode {
private:
T & data;
public:
AVLNode(T & newData) {
data = newData;
}
};

Resources