LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 08-18-2017, 09:33 AM   #1
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Rep: Reputation: 31
The right way of C++ class init() function


Hi all,
Could you teach me the right way of C++ class initialization function, init() ?
Code:
// This class is intended to be reused many times.
class ReusableMessage
{
	size_t len;
	int8_t *buf;
public:
	ReusableMessage( size_t n, int8_t *p )
		: len(n), buf(p)
	{
		init();
	}
	void init()
	{
		if (len && buf) memset( buf, 0, len );
	}
};

// Things look fine ?

class HelloMessage : public ReusableMessage
{
	hello_c_structure_t hello;
public:
	HelloMessage()
		: ReusableMessage( sizeof(hello), (int8_t*)&hello )
	{
		init();
	}
	void init()
	{
		ReusableMessage::init();
		hello.header[0] = 'H'; // e.g. something initialization to the structure.
	}
};

// calling init() in ctor() will call ReusableMessage::init() twice.
So, what is the right thing to do then?

Last edited by Jerry Mcguire; 08-18-2017 at 09:35 AM.
 
Old 08-18-2017, 09:50 AM   #2
a4z
Senior Member
 
Registered: Feb 2009
Posts: 1,727

Rep: Reputation: 742Reputation: 742Reputation: 742Reputation: 742Reputation: 742Reputation: 742Reputation: 742
you don not use a init function, you implement the init code direct in the costructor
better, you initialize your members direct.
do not use int8_t *buf and len as dynamic arrays,
use std::vector<int8_t>, it will make you more happy
 
Old 08-18-2017, 10:20 AM   #3
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Cannot use vector<> in my example. I need the pointer to a C structure.

OK. reset() was what I had intended when I first drafted this post.

Code:
// This class is intended to be reused many times.
class ReusableMessage
{
	size_t len;
	int8_t *buf;
	char state;
public:
	ReusableMessage( size_t n, int8_t *p )
		: len(n), buf(p), state(0)
	{
		reset();
	}
	void reset()
	{
		if (len && buf) memset( buf, 0, len );		
	}
};

// Things look fine ?

class HelloMessage : public ReusableMessage
{
	hello_c_structure_t hello;
	char target;
public:
	HelloMessage()
		: ReusableMessage( sizeof(hello), (int8_t*)&hello )
	{
		reset();
	}
	void reset()
	{
		ReusableMessage::reset();
		hello.header[0] = 'H'; // e.g. something initialization to the structure.
	}
};
Let's say I have the need to re-use the HelloMessage object again and again because I want to keep the state variable between uses. The C structure has to be reset every time which is why the memset() is not called in the ctor().

In this case how should reset()s and the ctor()s should be arranged?
 
Old 08-18-2017, 12:03 PM   #4
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 16,200

Rep: Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419
you should insert trace messages into your code to see what's happening, or probably you may try a debugger to test it (ddd).
Trace means something like that:
Code:
printf("trace: %s class %s method %s", classname, methodname, checkpoint)
and you can call this function at the beginning of ctor, at the end, and whenever you want (checkpoint=start/end/whatever)

In general you do not need to call reset in HelloMessage, because it will be automatically invoked from the inherited constructor, but you will see that using those trace.
 
1 members found this post helpful.
Old 08-21-2017, 08:03 AM   #5
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Thank you for hinting. I think I found the right way:
Code:
class Message // name reduced for easy recognition
{
protected:
  size_t len;
  int8_t *buf;
public:
  virtual ~Message() {}
  Message() : len(0), buf(NULL)
  {
    // avoid calling class virtual functions in ctor()
  }
  virtual void reset()
  {
    if( len && buf) memset( buf, 0, len );
  }
};

class HelloMessage : public Message
{
protected:
  hello_c_struct_t hello;
public:
  virtual ~HelloMessage() {}
  HelloMessage()
  {
    // same, do not call reset() here
  }
  virtual void reset()   // <- here
  {
    len = sizeof(hello);
    buf = (int8_t*)&hello;

    Message::reset();

    hello.header[0] = 'H';
  }
};

...

// client code
Message *m = new HelloMessage;
if (m) {
  m->reset();  // call reset from client
  work( m ); // some operation on the object (point to)
  m->reset();  // reset for the next use
  work( m ); // the next use.
  ...
  delete m;
}
One thing I'm not sure about. Must the derived class define the virtual function `virtual void reset()` again or just `void reset()`? See above code marked '<- here'. What is the rule?

Last edited by Jerry Mcguire; 08-21-2017 at 08:10 AM.
 
Old 08-21-2017, 08:33 AM   #6
pan64
LQ Guru
 
Registered: Mar 2012
Location: Hungary
Distribution: debian/ubuntu/suse ...
Posts: 16,200

Rep: Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419Reputation: 5419
you must not implement a virtual function - or at least I think so -, therefore reset of class Message is wrong. But probably I missed something...
Would be nice to see how did you compile it. You ought to use -Wall
 
Old 08-21-2017, 12:03 PM   #7
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,590

Rep: Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908Reputation: 1908
Quote:
Originally Posted by pan64 View Post
you must not implement a virtual function
No, that's not the case. You may be conflating "virtual" with "pure virtual". Except that apparently even pure virtual functions can have an implementation:

https://en.wikipedia.org/wiki/Virtua...tual_functions
Quote:
Although pure virtual methods typically have no implementation in the class that declares them, pure virtual methods in C++ are permitted to contain an implementation in their declaring class, providing fallback or default behaviour that a derived class can delegate to, if appropriate.
Quote:
Originally Posted by Jerry Mcguire View Post
Must the derived class define the virtual function `virtual void reset()` again or just `void reset()`?
As far as I remember, both ways work. It's just a question of style.
 
Old 08-21-2017, 12:09 PM   #8
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
@Pan64 I don't get your reply or why. Please give more details.
 
Old 08-21-2017, 12:39 PM   #9
Jerry Mcguire
Member
 
Registered: Jul 2009
Location: Hong Kong SAR
Distribution: RedHat, Fedora
Posts: 201

Original Poster
Rep: Reputation: 31
Many web search results say that virtual-ness is propagated to the derived class. Even cplusplus.com has an example on Polymorphism that the derived class does not declare the virtual function with the 'virtual' keyword in the derived classes.

Anyway, my personal choice would be sticking with the 'virtual' keyword so that when writing the next derived class I would immediately know which function is virtual.

Thank you all. It was a good discussion and knowledge mining session.
 
Old 08-23-2017, 01:30 PM   #10
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 9,078
Blog Entries: 4

Rep: Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187
Methods such as init() and reset() (the names are not significant ...) are sometimes used to avoid timing issues, or simply by convention within a particular programming team. Constructors run in a somewhat-peculiar environment in which, sometimes, "things aren't quite set up yet." So, objects sometimes carry their own initialization and clean-up functions that are intended to be called separately, after the constructor has run and before the destructor. They can also be used to "recycle" an object for re-use, resetting it to its initial state. Programmers are obliged to make explicit calls to them. (The case that you illustrate, where the constructor calls the function, is not one that I commonly see.)

Last edited by sundialsvcs; 08-25-2017 at 08:06 PM.
 
Old 08-23-2017, 01:41 PM   #11
dugan
LQ Guru
 
Registered: Nov 2003
Location: Canada
Distribution: distro hopper
Posts: 9,985

Rep: Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568Reputation: 4568
Quote:
Originally Posted by sundialsvcs View Post
Methods such as init() and [font=courier]reset()[/i] (the names are not significant ...) are sometimes used to avoid timing issues, or simply by convention within a particular programming team. Constructors run in a somewhat-peculiar environment in which, sometimes, "things aren't quite set up yet." So, objects sometimes carry their own initialization and clean-up functions that are intended to be called separately, after the constructor has run and before the destructor. They can also be used to "recycle" an object for re-use, resetting it to its initial state. Programmers are obliged to make explicit calls to them. (The case that you illustrate, where the constructor calls the function, is not one that I commonly see.)
That's an antipattern.

It results in code that's not exception-safe. If you have code like that, you can't use exception-handling. If you do, you'll get resource leaks.

It's common because a lot of C++ code (Qt, for example) was designed back when exceptions weren't ready for production use.

Last edited by dugan; 08-23-2017 at 01:57 PM.
 
1 members found this post helpful.
Old 08-25-2017, 08:07 PM   #12
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 9,078
Blog Entries: 4

Rep: Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187Reputation: 3187
Quote:
Originally Posted by dugan View Post
That's an antipattern.

It results in code that's not exception-safe. If you have code like that, you can't use exception-handling. If you do, you'll get resource leaks.

It's common because a lot of C++ code (Qt, for example) was designed back when exceptions weren't ready for production use.
You are correct, and thank you for pointing that out.
 
  


Reply

Tags
c++, init


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Callback function pointer to Class function pronoob Programming 16 09-30-2016 02:09 AM
[SOLVED] Class callback function teapottwo Programming 2 01-12-2016 07:52 PM
[SOLVED] How can a friend function access a public function from a base class? lesca Programming 1 11-17-2010 01:56 PM
javascript - class / function in function jchambers Programming 3 06-15-2009 10:33 PM
how pass a class to a function aditya1 Programming 2 03-08-2005 09:02 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:17 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration