I have an abstract pseudo base class for some audio formats with 2 ctors - one works for the derived class but the other one gives me an error which i can´t solve.
It says that i can´t access the protected member declared in MP3, but why can it reach one ctor but not the other?
class Audioformat
{
protected:
string song="";
Audioformat(string s) :song(s) {};//This ctor gives me the error
Audioformat() { song = "unknown";}
public:
virtual void play()=0;
virtual void info() = 0;
virtual ~Audioformat() = 0 {};
};
class MP3 : public Audioformat
{
public:
using Audioformat::Audioformat;
void play() { cout << "pseudo-play" << endl; }
void info() { cout << song << endl; }
~MP3() { cout << "MP3" << endl; delete this; }
};
Here´s my main :
int main()
{
MP3 song1{};//WORKS
MP3 song2{ "random trash song" };//ERROR MP3::MP3(std::string) is inaccessible
play(song1);
info(song1);
getchar();
return 0;
}
Two reasons:
Using declarations alone do not suppresses the implicit declaration of a special class member. In this case the default c'tor ([namespace.udecl]/4):
the using-declaration does not by itself suppress the implicit
declaration of the derived class member
So a public default c'tor for MP3 is synthesized by the compiler, and invoked in your example.
The c'tors introduced by a using declaration basically have the same accessibility they had in the base class ([namespace.udecl]/19):
A using-declarator that names a constructor
does not create a synonym; instead, the additional constructors are
accessible if they would be accessible when used to construct an
object of the corresponding base class, and the accessibility of the
using-declaration is ignored.
So the c'tor taking a string is not accessible in main since it's protected in MP3 as well.
If you want to have a public c'tor in MP3 that accepts a std::string you have to define it in full, and forward to the base class c'tor explicitly:
public:
MP3(std::string s) : Audioformat(s) {}
Related
Suppose you wanted to reproduce the following Python snippet:
class Base:
name = "base"
def announce(self):
print(self.name)
class Derived(Base):
name = "derived"
Base().announce()
Derived().announce()
... which would output:
"base"
"derived"
Initially, you may be inclined to write something like the following:
#include <iostream>
#include <string>
struct Base {
std::string name = "base";
void announce() {
std::cout << name << std::endl;
}
};
struct Derived : public Base {
std::string name = "movie";
};
int main() {
Base().announce();
Derived().announce();
return 0;
}
But here Derived.name simply shadows Base.name. Calling Derived.announce() references Base.name and prints "base".
Is there any way to implement this behaviour? Ideally without class templates if possible.
C++ doesn't work like Python (which isn't surprising, they are two very different languages after all), and member variables defined in an inherited class really defines a new variable that is unrelated to the variables of the parent class.
One possible solution is to create a second (possibly protected) Base constructor which takes the name as an argument, and then the Derived class can use it to initialize the member:
struct Base {
Base() = default; // A defaulted default constructor
std::string name = "base";
void announce() {
std::cout << name << std::endl;
}
protected:
explicit Base(std::string name)
: name{ std::move(name) } // Initialize the member
{
}
};
struct Derived : public Base {
Derived()
: Base("movie") // Initialize the base class using the special constructor
{
}
};
The default Base default constructor is needed, because if you declare another constructor the compiler won't automatically generate a default constructor for you.
I am trying to understand usage of private constructors with inheritance (I am fairly new to C++) and in testing things have run into the following:
vestigial.cc: In constructor ‘ExtraSample::ExtraSample()’:
vestigial.cc:34:16: error: no matching function for call to ‘Sample::Sample()’
ExtraSample() {};
using this to compile: g++ -std=c++11 vestigial.cc
here is the code:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;
class Sample {
public:
~Sample(){
cout << name << " died " << endl;
};
void what() {
cout << name << " hat" << endl;
}
private:
Sample(const string n) {
name = n;
};
friend class SampleOwner;
string name;
};
class SampleOwner {
public:
static Sample* createSample(const string n) {
return new Sample(n);
}
};
class ExtraSample : Sample {
public:
private:
ExtraSample() {};
};
In summary - why is this code invalid?
Thank you!
When a derived class is initialized, the base class has to be initialized first. You can specify which base class constructor to call by mentioning the base class's name in a ctor-initializer in the derived class constructor. If you do not explicitly specify this, then the compiler attempts to call the base class's default constructor.
However, this base class has no default constructor, hence the error message. Note that you wouldn't be able to call Sample::Sample(string) anyway, since it's private, so effectively it's impossible to derive from Sample at all.
If you want the base class's constructor to be callable only by the derived class, make it protected instead!
Why is the code invalid?
The caller can not access the private constructor.
There are several ways to make it possible to call a private base class constructor.
modify base class to name the derived class as a friend
add a named constructor to the base class as either protected or public, and it can call the derived constructor. (the named constructor idiom methods are static)
modify the base class to name the function as a friend.
modify the private constructor to be protected
I was reading effective C++ and I couldn't really understand one of the mentioned benefit of initialization list.From what I understand is that initialization lists also help to avoid calling of unnecessary default constructors especially when they are not needed. So in order to test that I created a simple code example as such
class base
{
public:
base()
{
std::cout << "Default Constructor called \n";
}
base (int i)
{
std::cout << "Int constructor called \n";
}
};
class der : public base
{
private:
base b;
public:
der(int i):b(i)
{
std::cout << "Derived constructor called \n";
}
};
void main()
{
der d(12);
}
No where I assumed that only the int constructor will be called instead both the constructors of the base class are called. Could anyone please clarify this concept.
The problem is that you actually have 2 instances of base, one as a member and one as a base. Either change into der(int i):base(i),b(i) or remove the member.
Keep in mind that you are adding a member of type base to the der class, which also needs to be constructed. That member is being initialized with the constructor that doesn't take arguments. What you probably meant was:
class base
{
private:
int num;
public:
base()
{
std::cout << "Default Constructor called \n";
}
base (int i) : num(i)
{
std::cout << "Int constructor called \n";
}
};
class der : public base
{
private:
//base b;
public:
der(int i):base(i)
{
std::cout << "Derived constructor called \n";
}
};
void main()
{
der d(12);
}
der has two base instances, as explained by Ylisar. As base has default constructor, it will be implicitly called in der constructor.
Also C++ only supports below two forms of main function, there is no void main() in C++
§3.6.1 Main function
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a return type of type int, but
otherwise its type is implementation-defined. All implementations
shall allow both of the following definitions of main:
int main() { /* ... */ }
and
int main(int argc, char* argv[]) { /* ... */ }
In your der,There are two base class, one is for inheriting, another one is b(the member of der).
#include <fstream>
using namespace std;
ofstream out("order.out");
#define CLASS(ID) class ID { \
public: \
ID(int) { out << #ID " constructor\n"; } \
~ID() { out << #ID " destructor\n"; } \
};
CLASS(Base1);
CLASS(Member1);
CLASS(Member2);
CLASS(Member3);
CLASS(Member4);
class Derived1 : public Base1 {
Member1 m1;
Member2 m2;
public:
Derived1(int) : m2(1), m1(2), Base1(3) {
out << "Derived1 constructor\n";
}
~Derived1() {
out << "Derived1 destructor\n";
}
};
class Derived2 : public Derived1 {
Member3 m3;
Member4 m4;
public:
Derived2() : m3(1), Derived1(2), m4(3) {
out << "Derived2 constructor\n";
}
~Derived2() {
out << "Derived2 destructor\n";
}
};
int main() {
Derived2 d2;
}
"Note that the
constructors are not default constructors; they each have an int
argument. The argument itself has no identifier; its only reason for
existence is to force you to explicitly call the constructors in the
initializer list"
As the classes have a user-defined constructor and that user-defined
constructor is not the default constructor, there is no default
constructor available in those classes.
This makes it necessary to explicitly mention one of the available
constructors in the member initializer list of a derived class.
class Derived : public Base {
Derived() {} // fails to compile, no constructor Base::Base() available
Derived() : Base(3) {} // works
};
So much for what the code does and how it achieves it. I have no idea
why you should ever need something like that, but you never know.
What it means that the argument has no identifier - no name - and thus it is not used anywhere in the constructor.
But, when you make an object that belongs to the derived class, it's constructor calls the constructor of the parent class. Also, when you have an object member, you have to initialize it in your constructor.
If the parent class had a default (no-arguments) constructor, you would not have to call it at all - it would have been done automatically. Also, if you do not initialize the object member, it will be done automatically via the default constructor.
Since none of your classes actually have a default constructor, you have to explicitly call the parent class constructor, and also initialize members via their only existing constructor with one argument.
Using the unnamed argument in all the classes does just that - forces you to explicitly call their constructors, instead of just relying on the default constructor being called.
Providing a constructor that takes an argument prevents the compiler from synthesising a default constructor. This forces the user of the ID class to provide an int, which is discarded, when creating an instance of this class. I can see no practical application of this approach.
To simplify this demonstration code:
#include <iostream>
struct ID
{
ID(int)
{
std::cout << "ID constructor" << std::endl;
}
};
int main()
{
ID this_will_compile(0);
ID this_will_not_compile;
}
While the first creation of an instance of ID will succeed, the second attempt will fail. You compiler will tell you something like:
error: no matching function for call to ‘ID::ID()’
The same is true for deriving from such a class:
This will work...
struct DerivedWorking: public ID
{
DerivedWorking()
:ID(0)
{
}
};
Whereas this will not, because it doesn't provide an int to ID's constructor...
struct DerivedBroken: public ID
{
DerivedBroken()
{
}
};
Just wanted some clarification.
Should abstract base classes never have private members? For example
class abc{
public:
virtual void foo()=0;
private:
int myInt;
}
you can never access myInt since you cannot create an instance of abc and it will not be in a derived class since its private.
Is there any situation where you would use private members in abstract base classes or is this just wrong?
In C++ you can have an abstract class that has non pure virtual methods. In that case, and depending on the design it can make sense to have private members:
class base {
std::string name;
public:
base( std::string const & n ) : name(n) {}
std::string const & getName() const { return name; }
virtual void foo() = 0;
};
That code ensures that every object that derives from base has a name, that is set during construction and never changes during the lifetime of the object.
EDIT: For completion after Charles Bailey reminded me of it in his answer
You can also define pure-virtual functions, and in that case, private attributes could also make sense:
// with the above definition of base
void base::foo() {
std::cout << "My name is " << name << std::endl;
}
It's normally not advisable to have data members in an abstract class but there is nothing technically wrong with your example. In the implementation of foo, which is publicly accessible you can use myInt for whatever purposes you like.
For example:
class abc{
public:
virtual void foo()=0;
private:
int myInt;
};
class xyz : public abc
{
virtual void foo();
};
#include <iostream>
#include <ostream>
void xyz::foo()
{
std::cout << "xyz::foo()\n";
abc::foo();
}
void abc::foo()
{
std::cout << "abc::foo(): " << myInt++ << '\n';
}
#include <memory>
int main()
{
std::auto_ptr<abc> p( new xyz() ); // value-initialization important
p->foo();
p->foo();
}
Output:
xyz::foo()
abc::foo(): 0
xyz::foo()
abc::foo(): 1
Not all methods in an abstract base class must be pure virtual. You might have some methods which are useful to all subclasses. Thus if you have some functionality in the base class which is modifying internal state you would have private members for those.
If you use the Template Method design pattern (to implement the open/closed principle), it is quite common to have private members of an abstract base class.
As it stands, your example makes no sense.
However, abstract base classes are allowed to have member function definitions, which in turn are allowed to access private member data in the base class.
You can access Private Members through this shortcut way
Code is in PHP
abstract class myclass1
{
private $var="46789";
public function test($valuetoset)
{
echo $this->var = $valuetoset;
}
}
class myclass2 extends myclass1
{
}
$obj = new myclass2();
$obj->test(78);