LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Basic C++ OOP - Constructors (https://www.linuxquestions.org/questions/programming-9/basic-c-oop-constructors-4175423068/)

mreff555 08-20-2012 09:22 AM

Basic C++ OOP - Constructors
 
I have a dumb question about constructors. As I was beginning to ask another question I think I just figured out what I did wrong.

If I have a constructor with arguments, is the constructor called when I create the object, or when I pass arguments to it? for example, I have a class called PixelCount which has an argument in the constructor.

Code:

PixelCount x;    //here?
x(argv[1]);      //or here?


johnsfine 08-20-2012 09:40 AM

Quote:

Originally Posted by mreff555 (Post 4759197)
If I have a constructor with arguments, is the constructor called when I create the object, or when I pass arguments to it?

Those should not be two separate statements. Have you tried compiling your code? Without seeing more code, I can't be sure, but I suspect your error should be caught at compile time, rather than do the wrong thing at run time.

Quote:

Code:

PixelCount x;    //here?
x(argv[1]);      //or here?


The default constructor is called by the first of those lines. If there is no default constructor, that is a compile time error.

The second line does not call any constructor nor pass an argument to one. It calls the object's operator() function and is a compile time error if that is not defined.

I think the code you intended is:
Code:

PixelCount x(argv[1]);

mreff555 08-20-2012 10:13 AM

Alright here is my problem. I am new to Programming and C++, very new to classes and object oriented programming. Here is the include and source for a small class I'm working on.

Code:

#include <opencv/cv.h>
#include <opencv/highgui.h>
#ifndef PIXELCOUNT_H
#define PIXELCOUNT_H
class PixelCount
{
    unsigned long white,black;
    public:
    IplImage* img;
    PixelCount(char*);
    void init(unsigned long, unsigned long);
    unsigned long getArea();
    unsigned long getWhite();
    unsigned long getBlack();

    virtual ~PixelCount();
    protected:
    private:
};

#endif // PIXELCOUNT_H

Code:

#include "include/PixelCount.h"
PixelCount::PixelCount(char* infile):
img(cvLoadImage(infile,0))
{

}
unsigned long getArea() {return (img)->width* (img)->height;}
unsigned long getWhite() {return cvCountNonZero(img);}
unsigned long getBlack() {return getArea()-getWhite();}

PixelCount::~PixelCount(){
    cvReleaseImage(&img);
    }

what I want to be able to do is to create an object from an argument and then have the function implicitly refer to the image so I don't have to give them arguments again. I have tried everything and I can't get it to work. Here is an example of what I want to be able to do:

Code:

PixelCount x(argv[1]);
std::cout << "Number of black pixels:" << x.getBlack() <<endl;

what am I doing wrong?

dwhitney67 08-20-2012 10:51 AM

Quote:

Originally Posted by mreff555 (Post 4759245)
what am I doing wrong?

You have not fully indicated what is it that you did, and what results you are seeing. I do not know OpenCV at all, however with 5 minutes of Googling to see examples of the API, and a little creative guessing to install the relevant libraries on my system, I got a program that is very similar to yours to function "properly".

Here it is:
Code:

#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <cassert>
#include <iostream>

class PixelCount
{
public:
    PixelCount(const char* imageFilename)
        : img(cvLoadImage(imageFilename, 0))
    {
        assert(img != NULL);
    }

    virtual ~PixelCount()
    {
        cvReleaseImage(&img);
    }

    unsigned long getArea() const  { return img->width * img->height; }
    unsigned long getWhite() const { return cvCountNonZero(img); }
    unsigned long getBlack() const { return getArea()-getWhite(); }

private:
    IplImage* img;
};

int main(int argc, char** argv)
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " <image>" << std::endl;
        return -1;
    }

    PixelCount pc(argv[1]);

    std::cout << "area : " << pc.getArea()  << std::endl;
    std::cout << "white: " << pc.getWhite() << std::endl;
    std::cout << "black: " << pc.getBlack() << std::endl;
}

To build the code:
Code:

g++ `pkg-config opencv --cflags` PixelCount.cpp `pkg-config opencv --libs`
To run it:
Code:

./a.out image.jpg

mreff555 08-20-2012 02:48 PM

Quote:

You have not fully indicated what is it that you did, and what results you are seeing.
If that's the case you did an excellent job extrapolating!

Quote:

I do not know OpenCV at all, however with 5 minutes of Googling to see examples of the API, and a little creative guessing to install the relevant libraries on my system, I got a program that is very similar to yours to function "properly".
Congratulations. I guess that's why you are considered a "senior member." Pardon me if I came off as someone who toils on a problem for five minutes and posts, wasting everyone's precious time. I just spent Thursday, Friday, the better part of the weekend, and half of today working on it. Thanks for making me feel retarded.

My original code, which did worked looked quite similar to yours. The problems arose when I attempted to separate the class/include.
It turns out that the problem was that I was not preceeding function names with "<classname>::" in the source files. Something I didn't have to do in the past when it was all in one file.

Anyway, I appreciate you help. Just not the attitude. It's easy to look up information if you already know what you are doing? and not everyone who posts is just looking for quick answers.

NevemTeve 08-20-2012 05:15 PM

> > You have not fully indicated what is it that you did, and what results you are seeing.
> If that's the case you did an excellent job extrapolating!

Yes he did, but next time you're asking for help don't rely on that: quote the actual error-message you got from the compiler/linker instead, and paste the relevant pieces of source.

sundialsvcs 08-20-2012 07:26 PM

Keep this in mind: a "constructor" is just an initialization subroutine. That's it, that's all.

When C++ is told to instantiate a new object (and remember, it must be explicitly told to do so...), it basically does two things in this order:
  1. It allocates a storage block of the appropriate size and (IIRC) sets it to zero.
  2. It invokes the constructor, if any, which usually invokes all the other constructors up the class-hierarchy chain.
More than one constructor can be defined, depending on the argument-list (if any...) that is provided, but the essential purpose is always exactly the same: "I have allocated a storage block for you... now, get it ready for use... whatever that may mean to you. (Hey, gimme a break, I'm just a programming-language... I have no idea.)"

A destructor, of course, is the opposite: "I'm getting ready to destroy this storage-block. If it refers to anything else that needs to be terminated or destroyed, please do so now."

johnsfine 08-21-2012 06:43 AM

Quote:

Originally Posted by sundialsvcs (Post 4759635)
It allocates a storage block of the appropriate size and (IIRC) sets it to zero.

No, it doesn't set it to zero.

The OS sets memory to zero before giving memory to the process (excepting cases where the memory is given with predefined contents, such as a file mapping).

In a simple program, the memory used within the process, (heap, stack, static or global) for a new object is typically memory the run time library has received zero filled from the OS, so it is typically zero before the constructor is executed, suppressing the symptoms of many common bugs in classes that don't initialize everything they should in their constructors.

But in more complex programs, memory for a new object (heap or stack) is more typically memory released from some earlier use within the same process, not zero filled memory newly received from the OS, so those bugs start to have symptoms.

sundialsvcs 08-21-2012 08:12 AM

Quote:

Originally Posted by johnsfine (Post 4759997)
No, it doesn't set it to zero.

The OS sets memory to zero before giving memory to the process (excepting cases where the memory is given with predefined contents, such as a file mapping).

In a simple program, the memory used within the process, (heap, stack, static or global) for a new object is typically memory the run time library has received zero filled from the OS, so it is typically zero before the constructor is executed, suppressing the symptoms of many common bugs in classes that don't initialize everything they should in their constructors.

But in more complex programs, memory for a new object (heap or stack) is more typically memory released from some earlier use within the same process, not zero filled memory newly received from the OS, so those bugs start to have symptoms.

Ahh, drat. Because the Delphi language (in Win32), and the C# follow-on language (designed by the same guy ...) does set the entire memory space of a newly-minted object to known-zeros. I was under the impression for some reason that C++ did the same. Anyhow, it is hugely beneficial IMHO when a language is architected to do this for you: all local-variables are zero / false / empty-string, guaranteed. And it basically only requires that the language's runtime system uses calloc instead of malloc calls internally ...


All times are GMT -5. The time now is 09:46 AM.